2 * Copyright (C) 1998, 1989 Transarc Corporation - All rights reserved
4 * (C) COPYRIGHT IBM CORPORATION 1987, 1988
5 * LICENSED MATERIALS - PROPERTY OF IBM
10 #include <afs/param.h>
26 extern smb_vc_t *dead_vcp;
28 extern osi_hyper_t hzero;
30 smb_packet_t *smb_Directory_Watches = NULL;
31 osi_mutex_t smb_Dir_Watch_Lock;
33 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
35 /* protected by the smb_globalLock */
36 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
38 /* retrieve a held reference to a user structure corresponding to an incoming
40 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
45 uidp = smb_FindUID(vcp, inp->uid, 0);
46 if (!uidp) return NULL;
48 lock_ObtainMutex(&uidp->mx);
51 lock_ReleaseMutex(&uidp->mx);
59 * Return extended attributes.
60 * Right now, we aren't using any of the "new" bits, so this looks exactly
61 * like smb_Attributes() (see smb.c).
63 unsigned long smb_ExtAttributes(cm_scache_t *scp)
67 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
68 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
73 * We used to mark a file RO if it was in an RO volume, but that
74 * turns out to be impolitic in NT. See defect 10007.
77 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
79 if ((scp->unixModeBits & 0222) == 0)
80 attrs |= 1; /* Read-only */
83 attrs = 0x80; /* FILE_ATTRIBUTE_NORMAL */
88 int smb_V3IsStarMask(char *maskp)
93 if (tc == '?' || tc == '*') return 1;
97 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
100 /* skip over null-terminated string */
101 *chainpp = inp + strlen(inp) + 1;
106 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
109 char *usern, *pwd, *pwdx;
110 smb_user_t *uidp, *dead_uidp;
111 unsigned short newUid;
116 /* Check for bad conns */
117 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
118 return CM_ERROR_REMOTECONN;
120 /* For NT LM 0.12 and up, get capabilities */
121 if (vcp->flags & SMB_VCFLAG_USENT) {
122 caps = smb_GetSMBParm(inp, 11);
124 vcp->flags |= SMB_VCFLAG_STATUS32;
125 /* for now, ignore other capability bits */
129 tp = smb_GetSMBData(inp, NULL);
130 if (vcp->flags & SMB_VCFLAG_USENT)
131 pwdx = smb_ParseString(tp, &tp);
132 pwd = smb_ParseString(tp, &tp);
133 usern = smb_ParseString(tp, &tp);
135 /* Create a new UID and cm_user_t structure */
136 userp = cm_NewUser();
137 lock_ObtainMutex(&vcp->mx);
138 newUid = vcp->uidCounter++;
139 lock_ReleaseMutex(&vcp->mx);
141 /* Create a new smb_user_t structure and connect them up */
142 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
143 lock_ObtainMutex(&uidp->mx);
145 uidp->name = strdup(usern);
146 lock_ReleaseMutex(&uidp->mx);
147 smb_ReleaseUID(uidp);
150 dead_uidp = dead_vcp->usersp;
153 && strcmp(dead_uidp->name, usern) == 0)
155 dead_uidp = dead_uidp->nextp;
159 /* transfer tokens from dead vcp */
160 if (dead_vcp && dead_uidp) {
161 cm_user_t *dead_userp;
162 s1 = ", tokens from terminated session";
163 dead_userp = dead_uidp->userp;
164 cm_ResetACLCache(dead_userp);
165 userp->cellInfop = dead_userp->cellInfop;
166 dead_userp->cellInfop = NULL;
170 /* transfer tokens from integrated logon */
171 if (vcp->logonDLLUser) {
172 s1 = ", tokens from integrated logon";
173 cm_ResetACLCache(vcp->logonDLLUser);
174 userp->cellInfop = vcp->logonDLLUser->cellInfop;
175 vcp->logonDLLUser->cellInfop = NULL;
176 vcp->logonDLLUser = NULL;
179 /* transfer tokens for logoff profile upload */
180 if (vcp->justLoggedOut) {
181 cm_user_t *logout_userp;
182 if (GetTickCount() - vcp->logoffTime <
183 1000 * smb_LogoffTransferTimeout
184 && strcmp(vcp->justLoggedOut->name, usern) == 0) {
185 s1 = ", tokens from logoff";
186 logout_userp = vcp->justLoggedOut->userp;
187 cm_ResetACLCache(logout_userp);
188 userp->cellInfop = logout_userp->cellInfop;
189 logout_userp->cellInfop = NULL;
191 vcp->justLoggedOut = NULL;
193 else if (loggedOut) {
194 cm_user_t *logout_userp;
195 if (GetTickCount() - loggedOutTime <
196 1000 * smb_LogoffTransferTimeout
197 && strcmp(loggedOutName, usern) == 0) {
198 s1 = ", tokens from logoff";
199 logout_userp = loggedOutUserp->userp;
200 cm_ResetACLCache(logout_userp);
201 userp->cellInfop = logout_userp->cellInfop;
202 logout_userp->cellInfop = NULL;
204 smb_ReleaseUID(loggedOutUserp);
205 loggedOutUserp = NULL;
207 loggedOutName = NULL;
211 /* Return UID to the client */
212 ((smb_t *)outp)->uid = newUid;
213 /* Also to the next chained message */
214 ((smb_t *)inp)->uid = newUid;
216 osi_Log3(afsd_logp, "SMB3 session setup name %s creating ID %d%s",
217 osi_LogSaveString(afsd_logp, usern), newUid, osi_LogSaveString(afsd_logp, s1));
218 smb_SetSMBParm(outp, 2, 0);
219 smb_SetSMBDataLength(outp, 0);
223 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
227 /* don't get tokens from this VC */
228 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
230 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
232 /* find the tree and free it */
233 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
235 char *s1 = NULL, *s2 = NULL;
237 /* Also, this is not logon session any more */
238 if (uidp->userp == vcp->logonDLLUser) {
239 s1 = ", was logon session";
240 vcp->logonDLLUser = NULL;
243 /* But its tokens might be needed later */
244 if (uidp->userp && !(uidp->userp->flags & CM_USERFLAG_WASLOGON)
245 && smb_LogoffTokenTransfer) {
246 s2 = ", pre-logout effect";
247 vcp->justLoggedOut = uidp;
248 vcp->logoffTime = GetTickCount();
251 if (s2 == NULL) s2 = " ";
252 if (s1 == NULL) {s1 = s2; s2 = " ";}
254 osi_Log4(afsd_logp, "SMB3 user logoffX uid %d name %s%s%s",
256 osi_LogSaveString(afsd_logp, uidp->name),
259 lock_ObtainMutex(&uidp->mx);
260 uidp->flags |= SMB_USERFLAG_DELETE;
262 * it doesn't get deleted right away
263 * because the vcp points to it
265 lock_ReleaseMutex(&uidp->mx);
268 osi_Log0(afsd_logp, "SMB3 user logoffX");
270 smb_SetSMBDataLength(outp, 0);
274 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
277 unsigned short newTid;
287 osi_Log0(afsd_logp, "SMB3 receive tree connect");
289 /* parse input parameters */
290 tp = smb_GetSMBData(inp, NULL);
291 passwordp = smb_ParseString(tp, &tp);
292 pathp = smb_ParseString(tp, &tp);
293 servicep = smb_ParseString(tp, &tp);
295 tp = strrchr(pathp, '\\');
297 return CM_ERROR_BADSMB;
299 strcpy(shareName, tp+1);
301 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0)
302 return CM_ERROR_NOIPC;
304 userp = smb_GetUser(vcp, inp);
306 lock_ObtainMutex(&vcp->mx);
307 newTid = vcp->tidCounter++;
308 lock_ReleaseMutex(&vcp->mx);
310 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
311 shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
313 smb_ReleaseTID(tidp);
314 return CM_ERROR_BADSHARENAME;
316 lock_ObtainMutex(&tidp->mx);
318 tidp->pathname = sharePath;
319 lock_ReleaseMutex(&tidp->mx);
320 smb_ReleaseTID(tidp);
322 if (vcp->flags & SMB_VCFLAG_USENT)
323 smb_SetSMBParm(outp, 2, 0); /* OptionalSupport bits */
325 ((smb_t *)outp)->tid = newTid;
326 ((smb_t *)inp)->tid = newTid;
327 tp = smb_GetSMBData(outp, NULL);
331 smb_SetSMBDataLength(outp, 3);
333 osi_Log1(afsd_logp, "SMB3 tree connect created ID %d", newTid);
337 /* must be called with global tran lock held */
338 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
340 smb_tran2Packet_t *tp;
343 smbp = (smb_t *) inp->data;
344 for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
345 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
351 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
352 int totalParms, int totalData)
354 smb_tran2Packet_t *tp;
357 smbp = (smb_t *) inp->data;
358 tp = malloc(sizeof(*tp));
359 memset(tp, 0, sizeof(*tp));
362 tp->curData = tp->curParms = 0;
363 tp->totalData = totalData;
364 tp->totalParms = totalParms;
369 tp->res[0] = smbp->res[0];
370 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
371 tp->opcode = smb_GetSMBParm(inp, 14);
373 tp->parmsp = malloc(totalParms);
375 tp->datap = malloc(totalData);
376 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
380 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
381 smb_tran2Packet_t *inp, smb_packet_t *outp,
382 int totalParms, int totalData)
384 smb_tran2Packet_t *tp;
385 unsigned short parmOffset;
386 unsigned short dataOffset;
387 unsigned short dataAlign;
389 tp = malloc(sizeof(*tp));
390 memset(tp, 0, sizeof(*tp));
392 tp->curData = tp->curParms = 0;
393 tp->totalData = totalData;
394 tp->totalParms = totalParms;
395 tp->oldTotalParms = totalParms;
400 tp->res[0] = inp->res[0];
401 tp->opcode = inp->opcode;
404 * We calculate where the parameters and data will start.
405 * This calculation must parallel the calculation in
406 * smb_SendTran2Packet.
409 parmOffset = 10*2 + 35;
410 parmOffset++; /* round to even */
411 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
413 dataOffset = parmOffset + totalParms;
414 dataAlign = dataOffset & 2; /* quad-align */
415 dataOffset += dataAlign;
416 tp->datap = outp->data + dataOffset;
421 /* free a tran2 packet; must be called with smb_globalLock held */
422 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
424 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
425 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
434 /* called with a VC, an input packet to respond to, and an error code.
435 * sends an error response.
437 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
438 smb_packet_t *tp, long code)
441 unsigned short errCode;
442 unsigned char errClass;
443 unsigned long NTStatus;
445 if (vcp->flags & SMB_VCFLAG_STATUS32)
446 smb_MapNTError(code, &NTStatus);
448 smb_MapCoreError(code, vcp, &errCode, &errClass);
450 smb_FormatResponsePacket(vcp, NULL, tp);
453 /* We can handle long names */
454 if (vcp->flags & SMB_VCFLAG_USENT)
455 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
457 /* now copy important fields from the tran 2 packet */
458 smbp->com = 0x32; /* tran 2 response */
459 smbp->tid = t2p->tid;
460 smbp->mid = t2p->mid;
461 smbp->pid = t2p->pid;
462 smbp->uid = t2p->uid;
463 smbp->res[0] = t2p->res[0];
464 if (vcp->flags & SMB_VCFLAG_STATUS32) {
465 smbp->rcls = (unsigned char) (NTStatus & 0xff);
466 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
467 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
468 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
469 smbp->flg2 |= 0x4000;
472 smbp->rcls = errClass;
473 smbp->errLow = (unsigned char) (errCode & 0xff);
474 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
478 smb_SendPacket(vcp, tp);
481 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
484 unsigned short parmOffset;
485 unsigned short dataOffset;
486 unsigned short totalLength;
487 unsigned short dataAlign;
490 smb_FormatResponsePacket(vcp, NULL, tp);
493 /* We can handle long names */
494 if (vcp->flags & SMB_VCFLAG_USENT)
495 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
497 /* now copy important fields from the tran 2 packet */
498 smbp->com = 0x32; /* tran 2 response */
499 smbp->tid = t2p->tid;
500 smbp->mid = t2p->mid;
501 smbp->pid = t2p->pid;
502 smbp->uid = t2p->uid;
503 smbp->res[0] = t2p->res[0];
505 totalLength = 1 + t2p->totalData + t2p->totalParms;
507 /* now add the core parameters (tran2 info) to the packet */
508 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
509 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
510 smb_SetSMBParm(tp, 2, 0); /* reserved */
511 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
512 parmOffset = 10*2 + 35; /* parm offset in packet */
513 parmOffset++; /* round to even */
514 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
515 * hdr, bcc and wct */
516 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
517 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
518 dataOffset = parmOffset + t2p->oldTotalParms;
519 dataAlign = dataOffset & 2; /* quad-align */
520 dataOffset += dataAlign;
521 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
522 smb_SetSMBParm(tp, 8, 0); /* data displacement */
523 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
526 datap = smb_GetSMBData(tp, NULL);
527 *datap++ = 0; /* we rounded to even */
529 totalLength += dataAlign;
530 smb_SetSMBDataLength(tp, totalLength);
532 /* next, send the datagram */
533 smb_SendPacket(vcp, tp);
536 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
538 smb_tran2Packet_t *asp;
550 /* We sometimes see 0 word count. What to do? */
551 if (*inp->wctp == 0) {
555 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0");
557 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
558 ptbuf[0] = "Transaction2 word count = 0";
559 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
560 1, inp->ncb_length, ptbuf, inp);
561 DeregisterEventSource(h);
563 smb_SetSMBDataLength(outp, 0);
564 smb_SendPacket(vcp, outp);
568 totalParms = smb_GetSMBParm(inp, 0);
569 totalData = smb_GetSMBParm(inp, 1);
571 firstPacket = (inp->inCom == 0x32);
573 /* find the packet we're reassembling */
574 lock_ObtainWrite(&smb_globalLock);
575 asp = smb_FindTran2Packet(vcp, inp);
577 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
579 lock_ReleaseWrite(&smb_globalLock);
581 /* now merge in this latest packet; start by looking up offsets */
583 parmDisp = dataDisp = 0;
584 parmOffset = smb_GetSMBParm(inp, 10);
585 dataOffset = smb_GetSMBParm(inp, 12);
586 parmCount = smb_GetSMBParm(inp, 9);
587 dataCount = smb_GetSMBParm(inp, 11);
588 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
589 asp->maxReturnData = smb_GetSMBParm(inp, 3);
591 osi_Log3(afsd_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
592 totalData, dataCount, asp->maxReturnData);
595 parmDisp = smb_GetSMBParm(inp, 4);
596 parmOffset = smb_GetSMBParm(inp, 3);
597 dataDisp = smb_GetSMBParm(inp, 7);
598 dataOffset = smb_GetSMBParm(inp, 6);
599 parmCount = smb_GetSMBParm(inp, 2);
600 dataCount = smb_GetSMBParm(inp, 5);
602 osi_Log2(afsd_logp, "SMB3 received T2 aux packet parms %d, data %d",
603 parmCount, dataCount);
606 /* now copy the parms and data */
607 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
608 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
610 /* account for new bytes */
611 asp->curData += dataCount;
612 asp->curParms += parmCount;
614 /* finally, if we're done, remove the packet from the queue and dispatch it */
615 if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
616 /* we've received it all */
617 lock_ObtainWrite(&smb_globalLock);
618 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
619 lock_ReleaseWrite(&smb_globalLock);
621 /* now dispatch it */
622 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
624 /* if an error is returned, we're supposed to send an error packet,
625 * otherwise the dispatched function already did the data sending.
626 * We give dispatched proc the responsibility since it knows how much
630 smb_SendTran2Error(vcp, asp, outp, code);
633 /* free the input tran 2 packet */
634 lock_ObtainWrite(&smb_globalLock);
635 smb_FreeTran2Packet(asp);
636 lock_ReleaseWrite(&smb_globalLock);
638 else if (firstPacket) {
639 /* the first packet in a multi-packet request, we need to send an
640 * ack to get more data.
642 smb_SetSMBDataLength(outp, 0);
643 smb_SendPacket(vcp, outp);
649 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
652 smb_tran2Packet_t *outp;
657 cm_scache_t *dscp; /* dir we're dealing with */
658 cm_scache_t *scp; /* file we're creating */
670 int parmSlot; /* which parm we're dealing with */
679 extraInfo = (p->parmsp[0] & 1); /* return extra info */
680 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
682 openFun = p->parmsp[6]; /* open function */
683 excl = ((openFun & 3) == 0);
684 trunc = ((openFun & 3) == 2); /* truncate it */
685 openMode = (p->parmsp[1] & 0x7);
686 openAction = 0; /* tracks what we did */
688 attributes = p->parmsp[3];
689 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
691 /* compute initial mode bits based on read-only flag in attributes */
692 initialModeBits = 0666;
693 if (attributes & 1) initialModeBits &= ~0222;
695 pathp = (char *) (&p->parmsp[14]);
697 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
699 spacep = cm_GetSpace();
700 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
702 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
703 /* special case magic file name for receiving IOCTL requests
704 * (since IOCTL calls themselves aren't getting through).
706 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
707 smb_SetupIoctlFid(fidp, spacep);
709 /* copy out remainder of the parms */
711 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
713 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
714 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
715 outp->parmsp[parmSlot] = 0; parmSlot++;
716 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
717 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
718 outp->parmsp[parmSlot] = openMode; parmSlot++;
719 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
720 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
722 /* and the final "always present" stuff */
723 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
724 /* next write out the "unique" ID */
725 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
726 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
727 outp->parmsp[parmSlot] = 0; parmSlot++;
728 if (returnEALength) {
729 outp->parmsp[parmSlot] = 0; parmSlot++;
730 outp->parmsp[parmSlot] = 0; parmSlot++;
734 outp->totalParms = parmSlot * 2;
736 smb_SendTran2Packet(vcp, outp, op);
738 smb_FreeTran2Packet(outp);
740 /* and clean up fid reference */
741 smb_ReleaseFID(fidp);
745 userp = smb_GetTran2User(vcp, p);
746 tidPathp = smb_GetTIDPath(vcp, p->tid);
749 code = cm_NameI(cm_rootSCachep, pathp,
750 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
751 userp, tidPathp, &req, &scp);
753 code = cm_NameI(cm_rootSCachep, spacep->data,
754 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
755 userp, tidPathp, &req, &dscp);
756 cm_FreeSpace(spacep);
759 cm_ReleaseUser(userp);
760 smb_FreeTran2Packet(outp);
764 /* otherwise, scp points to the parent directory. Do a lookup,
765 * and truncate the file if we find it, otherwise we create the
768 if (!lastNamep) lastNamep = pathp;
770 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
772 if (code && code != CM_ERROR_NOSUCHFILE) {
773 cm_ReleaseSCache(dscp);
774 cm_ReleaseUser(userp);
775 smb_FreeTran2Packet(outp);
780 cm_FreeSpace(spacep);
783 /* if we get here, if code is 0, the file exists and is represented by
784 * scp. Otherwise, we have to create it.
787 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
789 if (dscp) cm_ReleaseSCache(dscp);
790 cm_ReleaseSCache(scp);
791 cm_ReleaseUser(userp);
792 smb_FreeTran2Packet(outp);
797 /* oops, file shouldn't be there */
798 if (dscp) cm_ReleaseSCache(dscp);
799 cm_ReleaseSCache(scp);
800 cm_ReleaseUser(userp);
801 smb_FreeTran2Packet(outp);
802 return CM_ERROR_EXISTS;
806 setAttr.mask = CM_ATTRMASK_LENGTH;
807 setAttr.length.LowPart = 0;
808 setAttr.length.HighPart = 0;
809 code = cm_SetAttr(scp, &setAttr, userp, &req);
810 openAction = 3; /* truncated existing file */
812 else openAction = 1; /* found existing file */
814 else if (!(openFun & 0x10)) {
815 /* don't create if not found */
816 if (dscp) cm_ReleaseSCache(dscp);
817 osi_assert(scp == NULL);
818 cm_ReleaseUser(userp);
819 smb_FreeTran2Packet(outp);
820 return CM_ERROR_NOSUCHFILE;
823 osi_assert(dscp != NULL && scp == NULL);
824 openAction = 2; /* created file */
825 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
826 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
827 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
829 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
830 smb_NotifyChange(FILE_ACTION_ADDED,
831 FILE_NOTIFY_CHANGE_FILE_NAME,
832 dscp, lastNamep, NULL, TRUE);
833 if (!excl && code == CM_ERROR_EXISTS) {
834 /* not an exclusive create, and someone else tried
835 * creating it already, then we open it anyway. We
836 * don't bother retrying after this, since if this next
837 * fails, that means that the file was deleted after we
840 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
844 setAttr.mask = CM_ATTRMASK_LENGTH;
845 setAttr.length.LowPart = 0;
846 setAttr.length.HighPart = 0;
847 code = cm_SetAttr(scp, &setAttr, userp,
850 } /* lookup succeeded */
854 /* we don't need this any longer */
855 if (dscp) cm_ReleaseSCache(dscp);
858 /* something went wrong creating or truncating the file */
859 if (scp) cm_ReleaseSCache(scp);
860 cm_ReleaseUser(userp);
861 smb_FreeTran2Packet(outp);
865 /* make sure we're about to open a file */
866 if (scp->fileType != CM_SCACHETYPE_FILE) {
867 cm_ReleaseSCache(scp);
868 cm_ReleaseUser(userp);
869 smb_FreeTran2Packet(outp);
870 return CM_ERROR_ISDIR;
873 /* now all we have to do is open the file itself */
874 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
877 /* save a pointer to the vnode */
880 /* compute open mode */
881 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
882 if (openMode == 1 || openMode == 2)
883 fidp->flags |= SMB_FID_OPENWRITE;
885 smb_ReleaseFID(fidp);
887 cm_Open(scp, 0, userp);
889 /* copy out remainder of the parms */
891 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
892 lock_ObtainMutex(&scp->mx);
894 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
895 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
896 outp->parmsp[parmSlot] = dosTime & 0xffff; parmSlot++;
897 outp->parmsp[parmSlot] = (dosTime>>16) & 0xffff; parmSlot++;
898 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
900 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
902 outp->parmsp[parmSlot] = openMode; parmSlot++;
903 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
904 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
906 /* and the final "always present" stuff */
907 outp->parmsp[parmSlot] = openAction; parmSlot++;
908 /* next write out the "unique" ID */
909 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
910 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
911 outp->parmsp[parmSlot] = 0; parmSlot++;
912 if (returnEALength) {
913 outp->parmsp[parmSlot] = 0; parmSlot++;
914 outp->parmsp[parmSlot] = 0; parmSlot++;
916 lock_ReleaseMutex(&scp->mx);
917 outp->totalData = 0; /* total # of data bytes */
918 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
920 smb_SendTran2Packet(vcp, outp, op);
922 smb_FreeTran2Packet(outp);
924 cm_ReleaseUser(userp);
925 /* leave scp held since we put it in fidp->scp */
929 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
931 return CM_ERROR_BADOP;
934 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
936 return CM_ERROR_BADOP;
939 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
941 smb_tran2Packet_t *outp;
942 smb_tran2QFSInfo_t qi;
945 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
947 osi_Log1(afsd_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
949 switch (p->parmsp[0]) {
950 case 1: responseSize = sizeof(qi.u.allocInfo); break;
951 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
952 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
953 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
954 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
955 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
956 default: return CM_ERROR_INVAL;
959 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
960 switch (p->parmsp[0]) {
963 qi.u.allocInfo.FSID = 0;
964 qi.u.allocInfo.sectorsPerAllocUnit = 1;
965 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
966 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
967 qi.u.allocInfo.bytesPerSector = 1024;
972 qi.u.volumeInfo.vsn = 1234;
973 qi.u.volumeInfo.vnCount = 4;
974 /* we're supposed to pad it out with zeroes to the end */
975 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
976 strcpy(qi.u.volumeInfo.label, "AFS");
981 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
982 qi.u.FSvolumeInfo.vsn = 1234;
983 qi.u.FSvolumeInfo.vnCount = 4;
984 strcpy(qi.u.FSvolumeInfo.label, "AFS");
990 temp.LowPart = 0x7fffffff;
991 qi.u.FSsizeInfo.totalAllocUnits = temp;
992 temp.LowPart = 0x3fffffff;
993 qi.u.FSsizeInfo.availAllocUnits = temp;
994 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
995 qi.u.FSsizeInfo.bytesPerSector = 1024;
1000 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
1001 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
1005 /* FS attribute info */
1006 /* attributes, defined in WINNT.H:
1007 * FILE_CASE_SENSITIVE_SEARCH 0x1
1008 * FILE_CASE_PRESERVED_NAMES 0x2
1009 * <no name defined> 0x4000
1010 * If bit 0x4000 is not set, Windows 95 thinks
1011 * we can't handle long (non-8.3) names,
1012 * despite our protestations to the contrary.
1014 qi.u.FSattributeInfo.attributes = 0x4003;
1015 qi.u.FSattributeInfo.maxCompLength = 255;
1016 qi.u.FSattributeInfo.FSnameLength = 6;
1017 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
1021 /* copy out return data, and set corresponding sizes */
1022 outp->totalParms = 0;
1023 outp->totalData = responseSize;
1024 memcpy(outp->datap, &qi, responseSize);
1026 /* send and free the packets */
1027 smb_SendTran2Packet(vcp, outp, op);
1028 smb_FreeTran2Packet(outp);
1033 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1035 return CM_ERROR_BADOP;
1038 struct smb_ShortNameRock {
1042 size_t shortNameLen;
1045 long cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
1048 struct smb_ShortNameRock *rockp;
1052 /* compare both names and vnodes, though probably just comparing vnodes
1053 * would be safe enough.
1055 if (stricmp(dep->name, rockp->maskp) != 0)
1057 if (ntohl(dep->fid.vnode) != rockp->vnode)
1059 /* This is the entry */
1060 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1061 rockp->shortNameLen = shortNameEnd - rockp->shortName;
1062 return CM_ERROR_STOPNOW;
1065 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1066 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1068 struct smb_ShortNameRock rock;
1072 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1076 spacep = cm_GetSpace();
1077 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1079 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1081 cm_FreeSpace(spacep);
1082 if (code) return code;
1084 if (!lastNamep) lastNamep = pathp;
1087 thyper.HighPart = 0;
1088 rock.shortName = shortName;
1090 rock.maskp = lastNamep;
1091 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1094 cm_ReleaseSCache(dscp);
1097 return CM_ERROR_NOSUCHFILE;
1098 if (code == CM_ERROR_STOPNOW) {
1099 *shortNameLenp = rock.shortNameLen;
1105 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1107 smb_tran2Packet_t *outp;
1108 unsigned long dosTime;
1110 unsigned short infoLevel;
1112 unsigned short attributes;
1113 unsigned long extAttributes;
1118 cm_scache_t *scp, *dscp;
1127 infoLevel = p->parmsp[0];
1128 if (infoLevel == 6) nbytesRequired = 0;
1129 else if (infoLevel == 1) nbytesRequired = 22;
1130 else if (infoLevel == 2) nbytesRequired = 26;
1131 else if (infoLevel == 0x101) nbytesRequired = 40;
1132 else if (infoLevel == 0x102) nbytesRequired = 24;
1133 else if (infoLevel == 0x103) nbytesRequired = 4;
1134 else if (infoLevel == 0x108) nbytesRequired = 30;
1136 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1137 p->opcode, infoLevel);
1138 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1141 osi_Log2(afsd_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1142 osi_LogSaveString(afsd_logp, (char *)(&p->parmsp[3])));
1144 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1146 if (infoLevel > 0x100)
1147 outp->totalParms = 2;
1149 outp->totalParms = 0;
1150 outp->totalData = nbytesRequired;
1152 /* now, if we're at infoLevel 6, we're only being asked to check
1153 * the syntax, so we just OK things now. In particular, we're *not*
1154 * being asked to verify anything about the state of any parent dirs.
1156 if (infoLevel == 6) {
1157 smb_SendTran2Packet(vcp, outp, opx);
1158 smb_FreeTran2Packet(outp);
1162 userp = smb_GetTran2User(vcp, p);
1164 tidPathp = smb_GetTIDPath(vcp, p->tid);
1167 * XXX Strange hack XXX
1169 * As of Patch 7 (13 January 98), we are having the following problem:
1170 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1171 * requests to look up "desktop.ini" in all the subdirectories.
1172 * This can cause zillions of timeouts looking up non-existent cells
1173 * and volumes, especially in the top-level directory.
1175 * We have not found any way to avoid this or work around it except
1176 * to explicitly ignore the requests for mount points that haven't
1177 * yet been evaluated and for directories that haven't yet been
1180 if (infoLevel == 0x101) {
1181 spacep = cm_GetSpace();
1182 smb_StripLastComponent(spacep->data, &lastComp,
1183 (char *)(&p->parmsp[3]));
1184 if (strcmp(lastComp, "\\desktop.ini") == 0) {
1185 code = cm_NameI(cm_rootSCachep, spacep->data,
1189 userp, tidPathp, &req, &dscp);
1191 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1192 && !dscp->mountRootFidp)
1193 code = CM_ERROR_NOSUCHFILE;
1194 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1195 cm_buf_t *bp = buf_Find(dscp, &hzero);
1199 code = CM_ERROR_NOSUCHFILE;
1201 cm_ReleaseSCache(dscp);
1203 cm_FreeSpace(spacep);
1204 cm_ReleaseUser(userp);
1205 smb_SendTran2Error(vcp, p, opx, code);
1206 smb_FreeTran2Packet(outp);
1211 cm_FreeSpace(spacep);
1214 /* now do namei and stat, and copy out the info */
1215 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1216 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1219 cm_ReleaseUser(userp);
1220 smb_SendTran2Error(vcp, p, opx, code);
1221 smb_FreeTran2Packet(outp);
1225 lock_ObtainMutex(&scp->mx);
1226 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1227 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1228 if (code) goto done;
1230 /* now we have the status in the cache entry, and everything is locked.
1231 * Marshall the output data.
1234 /* for info level 108, figure out short name */
1235 if (infoLevel == 0x108) {
1236 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1237 tidPathp, scp->fid.vnode, shortName,
1244 *((u_long *)op) = len * 2; op += 4;
1245 mbstowcs((unsigned short *)op, shortName, len);
1250 if (infoLevel == 1 || infoLevel == 2) {
1251 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1252 *((u_long *)op) = dosTime; op += 4; /* creation time */
1253 *((u_long *)op) = dosTime; op += 4; /* access time */
1254 *((u_long *)op) = dosTime; op += 4; /* write time */
1255 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1256 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1257 attributes = smb_Attributes(scp);
1258 *((u_short *)op) = attributes; op += 2; /* attributes */
1260 else if (infoLevel == 0x101) {
1261 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1262 *((FILETIME *)op) = ft; op += 8; /* creation time */
1263 *((FILETIME *)op) = ft; op += 8; /* last access time */
1264 *((FILETIME *)op) = ft; op += 8; /* last write time */
1265 *((FILETIME *)op) = ft; op += 8; /* last change time */
1266 extAttributes = smb_ExtAttributes(scp);
1267 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1268 *((u_long *)op) = 0; op += 4; /* don't know what this is */
1270 else if (infoLevel == 0x102) {
1271 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1272 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1273 *((u_long *)op) = scp->linkCount; op += 4;
1276 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1279 else if (infoLevel == 0x103) {
1280 memset(op, 0, 4); op += 4; /* EA size */
1283 /* now, if we are being asked about extended attrs, return a 0 size */
1284 if (infoLevel == 2) {
1285 *((u_long *)op) = 0; op += 4;
1289 /* send and free the packets */
1291 lock_ReleaseMutex(&scp->mx);
1292 cm_ReleaseSCache(scp);
1293 cm_ReleaseUser(userp);
1294 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1295 else smb_SendTran2Error(vcp, p, opx, code);
1296 smb_FreeTran2Packet(outp);
1301 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1303 return CM_ERROR_BADOP;
1306 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1308 smb_tran2Packet_t *outp;
1310 unsigned long attributes;
1311 unsigned short infoLevel;
1324 fidp = smb_FindFID(vcp, fid, 0);
1327 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
1331 infoLevel = p->parmsp[1];
1332 if (infoLevel == 0x101) nbytesRequired = 40;
1333 else if (infoLevel == 0x102) nbytesRequired = 24;
1334 else if (infoLevel == 0x103) nbytesRequired = 4;
1335 else if (infoLevel == 0x104) nbytesRequired = 6;
1337 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1338 p->opcode, infoLevel);
1339 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1342 osi_Log2(afsd_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1344 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1346 if (infoLevel > 0x100)
1347 outp->totalParms = 2;
1349 outp->totalParms = 0;
1350 outp->totalData = nbytesRequired;
1352 userp = smb_GetTran2User(vcp, p);
1355 lock_ObtainMutex(&scp->mx);
1356 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1357 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1358 if (code) goto done;
1360 /* now we have the status in the cache entry, and everything is locked.
1361 * Marshall the output data.
1364 if (infoLevel == 0x101) {
1365 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1366 *((FILETIME *)op) = ft; op += 8; /* creation time */
1367 *((FILETIME *)op) = ft; op += 8; /* last access time */
1368 *((FILETIME *)op) = ft; op += 8; /* last write time */
1369 *((FILETIME *)op) = ft; op += 8; /* last change time */
1370 attributes = smb_ExtAttributes(scp);
1371 *((u_long *)op) = attributes; op += 4;
1372 *((u_long *)op) = 0; op += 4;
1374 else if (infoLevel == 0x102) {
1375 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1376 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1377 *((u_long *)op) = scp->linkCount; op += 4;
1378 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1380 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1383 else if (infoLevel == 0x103) {
1384 *((u_long *)op) = 0; op += 4;
1386 else if (infoLevel == 0x104) {
1390 if (fidp->NTopen_wholepathp)
1391 name = fidp->NTopen_wholepathp;
1393 name = "\\"; /* probably can't happen */
1395 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
1396 *((u_long *)op) = len * 2; op += 4;
1397 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1400 /* send and free the packets */
1402 lock_ReleaseMutex(&scp->mx);
1403 cm_ReleaseUser(userp);
1404 smb_ReleaseFID(fidp);
1405 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1406 else smb_SendTran2Error(vcp, p, opx, code);
1407 smb_FreeTran2Packet(outp);
1412 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1417 unsigned short infoLevel;
1418 smb_tran2Packet_t *outp;
1426 fidp = smb_FindFID(vcp, fid, 0);
1429 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1433 infoLevel = p->parmsp[1];
1434 if (infoLevel > 0x104 || infoLevel < 0x101) {
1435 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1436 p->opcode, infoLevel);
1437 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1441 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1442 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1445 if ((infoLevel == 0x103 || infoLevel == 0x104)
1446 && !(fidp->flags & SMB_FID_OPENWRITE)) {
1447 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1451 osi_Log1(afsd_logp, "T2 SFileInfo type 0x%x", infoLevel);
1453 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1455 outp->totalParms = 2;
1456 outp->totalData = 0;
1458 userp = smb_GetTran2User(vcp, p);
1462 if (infoLevel == 0x101) {
1464 unsigned int attribute;
1467 /* lock the vnode with a callback; we need the current status
1468 * to determine what the new status is, in some cases.
1470 lock_ObtainMutex(&scp->mx);
1471 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1472 CM_SCACHESYNC_GETSTATUS
1473 | CM_SCACHESYNC_NEEDCALLBACK);
1475 lock_ReleaseMutex(&scp->mx);
1479 /* prepare for setattr call */
1481 lastMod = *((FILETIME *)(p->datap + 16));
1482 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod))) {
1483 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1484 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1486 fidp->flags |= SMB_FID_MTIMESETDONE;
1488 attribute = *((u_long *)(p->datap + 32));
1489 if (attribute != 0) {
1490 if ((scp->unixModeBits & 0222)
1491 && (attribute & 1) != 0) {
1492 /* make a writable file read-only */
1493 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1494 attr.unixModeBits = scp->unixModeBits & ~0222;
1496 else if ((scp->unixModeBits & 0222) == 0
1497 && (attribute & 1) == 0) {
1498 /* make a read-only file writable */
1499 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1500 attr.unixModeBits = scp->unixModeBits | 0222;
1503 lock_ReleaseMutex(&scp->mx);
1507 code = cm_SetAttr(scp, &attr, userp, &req);
1511 else if (infoLevel == 0x103 || infoLevel == 0x104) {
1512 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1515 attr.mask = CM_ATTRMASK_LENGTH;
1516 attr.length.LowPart = size.LowPart;
1517 attr.length.HighPart = size.HighPart;
1518 code = cm_SetAttr(scp, &attr, userp, &req);
1520 else if (infoLevel == 0x102) {
1521 if (*((char *)(p->datap))) {
1522 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1525 fidp->flags |= SMB_FID_DELONCLOSE;
1529 fidp->flags &= ~SMB_FID_DELONCLOSE;
1533 cm_ReleaseUser(userp);
1534 smb_ReleaseFID(fidp);
1535 if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1536 else smb_SendTran2Error(vcp, p, op, code);
1537 smb_FreeTran2Packet(outp);
1542 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1544 return CM_ERROR_BADOP;
1547 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1549 return CM_ERROR_BADOP;
1552 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1554 return CM_ERROR_BADOP;
1557 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1559 return CM_ERROR_BADOP;
1562 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1564 return CM_ERROR_BADOP;
1567 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1568 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1573 cm_scache_t *targetScp; /* target if scp is a symlink */
1578 unsigned short attr;
1579 unsigned long lattr;
1580 smb_dirListPatch_t *patchp;
1581 smb_dirListPatch_t *npatchp;
1583 for(patchp = *dirPatchespp; patchp; patchp =
1584 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1585 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1587 lock_ObtainMutex(&scp->mx);
1588 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1589 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1591 lock_ReleaseMutex(&scp->mx);
1592 cm_ReleaseSCache(scp);
1596 /* now watch for a symlink */
1597 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1598 lock_ReleaseMutex(&scp->mx);
1599 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp,
1602 /* we have a more accurate file to use (the
1603 * target of the symbolic link). Otherwise,
1604 * we'll just use the symlink anyway.
1606 osi_Log2(afsd_logp, "symlink vp %x to vp %x",
1608 cm_ReleaseSCache(scp);
1611 lock_ObtainMutex(&scp->mx);
1614 dptr = patchp->dptr;
1616 if (infoLevel >= 0x101) {
1618 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1620 /* copy to Creation Time */
1621 *((FILETIME *)dptr) = ft;
1624 /* copy to Last Access Time */
1625 *((FILETIME *)dptr) = ft;
1628 /* copy to Last Write Time */
1629 *((FILETIME *)dptr) = ft;
1632 /* copy to Change Time */
1633 *((FILETIME *)dptr) = ft;
1636 /* Use length for both file length and alloc length */
1637 *((LARGE_INTEGER *)dptr) = scp->length;
1639 *((LARGE_INTEGER *)dptr) = scp->length;
1642 /* Copy attributes */
1643 lattr = smb_ExtAttributes(scp);
1644 *((u_long *)dptr) = lattr;
1649 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1651 /* and copy out date */
1652 shortTemp = (dosTime>>16) & 0xffff;
1653 *((u_short *)dptr) = shortTemp;
1656 /* copy out creation time */
1657 shortTemp = dosTime & 0xffff;
1658 *((u_short *)dptr) = shortTemp;
1661 /* and copy out date */
1662 shortTemp = (dosTime>>16) & 0xffff;
1663 *((u_short *)dptr) = shortTemp;
1666 /* copy out access time */
1667 shortTemp = dosTime & 0xffff;
1668 *((u_short *)dptr) = shortTemp;
1671 /* and copy out date */
1672 shortTemp = (dosTime>>16) & 0xffff;
1673 *((u_short *)dptr) = shortTemp;
1676 /* copy out mod time */
1677 shortTemp = dosTime & 0xffff;
1678 *((u_short *)dptr) = shortTemp;
1681 /* copy out file length and alloc length,
1682 * using the same for both
1684 *((u_long *)dptr) = scp->length.LowPart;
1686 *((u_long *)dptr) = scp->length.LowPart;
1689 /* finally copy out attributes as short */
1690 attr = smb_Attributes(scp);
1691 *dptr++ = attr & 0xff;
1692 *dptr++ = (attr >> 8) & 0xff;
1695 lock_ReleaseMutex(&scp->mx);
1696 cm_ReleaseSCache(scp);
1699 /* now free the patches */
1700 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1701 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1705 /* and mark the list as empty */
1706 *dirPatchespp = NULL;
1711 /* do a case-folding search of the star name mask with the name in namep.
1712 * Return 1 if we match, otherwise 0.
1714 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1716 unsigned char tcp1, tcp2; /* Pattern characters */
1717 unsigned char tcn1; /* Name characters */
1718 int sawDot = 0, sawStar = 0;
1719 char *starNamep, *starMaskp;
1720 static char nullCharp[] = {0};
1722 /* make sure we only match 8.3 names, if requested */
1723 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) return 0;
1727 /* Next pattern character */
1730 /* Next name character */
1734 /* 0 - end of pattern */
1740 else if (tcp1 == '.' || tcp1 == '"') {
1750 * first dot in pattern;
1751 * must match dot or end of name
1756 else if (tcn1 == '.') {
1765 else if (tcp1 == '?') {
1766 if (tcn1 == 0 || tcn1 == '.')
1771 else if (tcp1 == '>') {
1772 if (tcn1 != 0 && tcn1 != '.')
1776 else if (tcp1 == '*' || tcp1 == '<') {
1780 else if (tcp2 == '.' || tcp2 == '"') {
1781 while (tcn1 != '.' && tcn1 != 0)
1796 * pattern character after '*' is not null or
1797 * period. If it is '?' or '>', we are not
1798 * going to understand it. If it is '*' or
1799 * '<', we are going to skip over it. None of
1800 * these are likely, I hope.
1802 /* skip over '*' and '<' */
1803 while (tcp2 == '*' || tcp2 == '<')
1806 /* skip over characters that don't match tcp2 */
1807 while (tcn1 != '.' && tcn1 != 0
1808 && cm_foldUpper[tcn1] != cm_foldUpper[tcp2])
1812 if (tcn1 == '.' || tcn1 == 0)
1815 /* Remember where we are */
1825 /* tcp1 is not a wildcard */
1826 if (cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) {
1831 /* if trying to match a star pattern, go back */
1833 maskp = starMaskp - 2;
1834 namep = starNamep + 1;
1844 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1853 smb_dirListPatch_t *dirListPatchesp;
1854 smb_dirListPatch_t *curPatchp;
1857 long orbytes; /* # of bytes in this output record */
1858 long ohbytes; /* # of bytes, except file name */
1859 long onbytes; /* # of bytes in name, incl. term. null */
1860 osi_hyper_t dirLength;
1861 osi_hyper_t bufferOffset;
1862 osi_hyper_t curOffset;
1864 smb_dirSearch_t *dsp;
1868 cm_pageHeader_t *pageHeaderp;
1869 cm_user_t *userp = NULL;
1872 long nextEntryCookie;
1873 int numDirChunks; /* # of 32 byte dir chunks in this entry */
1874 char *op; /* output data ptr */
1875 char *origOp; /* original value of op */
1876 cm_space_t *spacep; /* for pathname buffer */
1877 long maxReturnData; /* max # of return data */
1878 long maxReturnParms; /* max # of return parms */
1879 long bytesInBuffer; /* # data bytes in the output buffer */
1881 char *maskp; /* mask part of path */
1885 smb_tran2Packet_t *outp; /* response packet */
1888 char shortName[13]; /* 8.3 name if needed */
1897 if (p->opcode == 1) {
1898 /* find first; obtain basic parameters from request */
1899 attribute = p->parmsp[0];
1900 maxCount = p->parmsp[1];
1901 infoLevel = p->parmsp[3];
1902 searchFlags = p->parmsp[2];
1903 dsp = smb_NewDirSearch(1);
1904 dsp->attribute = attribute;
1905 pathp = ((char *) p->parmsp) + 12; /* points to path */
1907 maskp = strrchr(pathp, '\\');
1908 if (maskp == NULL) maskp = pathp;
1909 else maskp++; /* skip over backslash */
1910 strcpy(dsp->mask, maskp); /* and save mask */
1911 /* track if this is likely to match a lot of entries */
1912 starPattern = smb_V3IsStarMask(maskp);
1915 osi_assert(p->opcode == 2);
1916 /* find next; obtain basic parameters from request or open dir file */
1917 dsp = smb_FindDirSearch(p->parmsp[0]);
1918 if (!dsp) return CM_ERROR_BADFD;
1919 attribute = dsp->attribute;
1920 maxCount = p->parmsp[1];
1921 infoLevel = p->parmsp[2];
1922 searchFlags = p->parmsp[5];
1924 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
1926 starPattern = 1; /* assume, since required a Find Next */
1930 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
1931 attribute, infoLevel, maxCount, searchFlags);
1933 osi_Log2(afsd_logp, "...T2 search op %d, nextCookie 0x%x",
1934 p->opcode, nextCookie);
1936 if (infoLevel >= 0x101)
1937 searchFlags &= ~4; /* no resume keys */
1939 dirListPatchesp = NULL;
1941 maxReturnData = p->maxReturnData;
1942 if (p->opcode == 1) /* find first */
1943 maxReturnParms = 10; /* bytes */
1945 maxReturnParms = 8; /* bytes */
1947 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
1948 if (maxReturnData > 6000) maxReturnData = 6000;
1949 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
1951 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
1954 osi_Log1(afsd_logp, "T2 receive search dir %s",
1955 osi_LogSaveString(afsd_logp, pathp));
1957 /* bail out if request looks bad */
1958 if (p->opcode == 1 && !pathp) {
1959 return CM_ERROR_BADSMB;
1962 osi_Log2(afsd_logp, "T2 dir search cookie 0x%x, connection %d",
1963 nextCookie, dsp->cookie);
1965 userp = smb_GetTran2User(vcp, p);
1967 /* try to get the vnode for the path name next */
1968 lock_ObtainMutex(&dsp->mx);
1975 spacep = cm_GetSpace();
1976 smb_StripLastComponent(spacep->data, NULL, pathp);
1977 lock_ReleaseMutex(&dsp->mx);
1979 tidPathp = smb_GetTIDPath(vcp, p->tid);
1980 code = cm_NameI(cm_rootSCachep, spacep->data,
1981 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
1982 userp, tidPathp, &req, &scp);
1983 cm_FreeSpace(spacep);
1985 lock_ObtainMutex(&dsp->mx);
1987 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
1989 /* we need one hold for the entry we just stored into,
1990 * and one for our own processing. When we're done
1991 * with this function, we'll drop the one for our own
1992 * processing. We held it once from the namei call,
1993 * and so we do another hold now.
1996 lock_ObtainMutex(&scp->mx);
1997 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
1998 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
1999 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2000 dsp->flags |= SMB_DIRSEARCH_BULKST;
2002 lock_ReleaseMutex(&scp->mx);
2005 lock_ReleaseMutex(&dsp->mx);
2007 cm_ReleaseUser(userp);
2008 smb_FreeTran2Packet(outp);
2009 smb_DeleteDirSearch(dsp);
2010 smb_ReleaseDirSearch(dsp);
2014 /* get the directory size */
2015 lock_ObtainMutex(&scp->mx);
2016 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2017 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2019 lock_ReleaseMutex(&scp->mx);
2020 cm_ReleaseSCache(scp);
2021 cm_ReleaseUser(userp);
2022 smb_FreeTran2Packet(outp);
2023 smb_DeleteDirSearch(dsp);
2024 smb_ReleaseDirSearch(dsp);
2028 dirLength = scp->length;
2030 bufferOffset.LowPart = bufferOffset.HighPart = 0;
2031 curOffset.HighPart = 0;
2032 curOffset.LowPart = nextCookie;
2033 origOp = outp->datap;
2040 if (searchFlags & 4)
2041 /* skip over resume key */
2044 /* make sure that curOffset.LowPart doesn't point to the first
2045 * 32 bytes in the 2nd through last dir page, and that it doesn't
2046 * point at the first 13 32-byte chunks in the first dir page,
2047 * since those are dir and page headers, and don't contain useful
2050 temp = curOffset.LowPart & (2048-1);
2051 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2052 /* we're in the first page */
2053 if (temp < 13*32) temp = 13*32;
2056 /* we're in a later dir page */
2057 if (temp < 32) temp = 32;
2060 /* make sure the low order 5 bits are zero */
2063 /* now put temp bits back ito curOffset.LowPart */
2064 curOffset.LowPart &= ~(2048-1);
2065 curOffset.LowPart |= temp;
2067 /* check if we've returned all the names that will fit in the
2068 * response packet; we check return count as well as the number
2069 * of bytes requested. We check the # of bytes after we find
2070 * the dir entry, since we'll need to check its size.
2072 if (returnedNames >= maxCount) break;
2074 /* check if we've passed the dir's EOF */
2075 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2080 /* see if we can use the bufferp we have now; compute in which
2081 * page the current offset would be, and check whether that's
2082 * the offset of the buffer we have. If not, get the buffer.
2084 thyper.HighPart = curOffset.HighPart;
2085 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2086 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2089 buf_Release(bufferp);
2092 lock_ReleaseMutex(&scp->mx);
2093 lock_ObtainRead(&scp->bufCreateLock);
2094 code = buf_Get(scp, &thyper, &bufferp);
2095 lock_ReleaseRead(&scp->bufCreateLock);
2097 /* now, if we're doing a star match, do bulk fetching
2098 * of all of the status info for files in the dir.
2101 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2104 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2105 && LargeIntegerGreaterThanOrEqualTo(
2106 thyper, scp->bulkStatProgress)) {
2107 /* Don't bulk stat if risking timeout */
2108 int now = GetCurrentTime();
2109 if (now - req.startTime > 5000) {
2110 scp->bulkStatProgress = thyper;
2111 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2112 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2114 cm_TryBulkStat(scp, &thyper,
2119 lock_ObtainMutex(&scp->mx);
2121 bufferOffset = thyper;
2123 /* now get the data in the cache */
2125 code = cm_SyncOp(scp, bufferp, userp, &req,
2127 CM_SCACHESYNC_NEEDCALLBACK
2128 | CM_SCACHESYNC_READ);
2131 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2133 /* otherwise, load the buffer and try again */
2134 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2139 buf_Release(bufferp);
2143 } /* if (wrong buffer) ... */
2145 /* now we have the buffer containing the entry we're interested
2146 * in; copy it out if it represents a non-deleted entry.
2148 entryInDir = curOffset.LowPart & (2048-1);
2149 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2151 /* page header will help tell us which entries are free. Page
2152 * header can change more often than once per buffer, since
2153 * AFS 3 dir page size may be less than (but not more than)
2154 * a buffer package buffer.
2156 /* only look intra-buffer */
2157 temp = curOffset.LowPart & (buf_bufferSize - 1);
2158 temp &= ~(2048 - 1); /* turn off intra-page bits */
2159 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2161 /* now determine which entry we're looking at in the page.
2162 * If it is free (there's a free bitmap at the start of the
2163 * dir), we should skip these 32 bytes.
2165 slotInPage = (entryInDir & 0x7e0) >> 5;
2166 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2167 & (1 << (slotInPage & 0x7)))) {
2168 /* this entry is free */
2169 numDirChunks = 1; /* only skip this guy */
2173 tp = bufferp->datap + entryInBuffer;
2174 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
2176 /* while we're here, compute the next entry's location, too,
2177 * since we'll need it when writing out the cookie into the dir
2180 * XXXX Probably should do more sanity checking.
2182 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2184 /* compute offset of cookie representing next entry */
2185 nextEntryCookie = curOffset.LowPart
2186 + (CM_DIR_CHUNKSIZE * numDirChunks);
2188 /* Need 8.3 name? */
2190 if (infoLevel == 0x104
2191 && dep->fid.vnode != 0
2192 && !cm_Is8Dot3(dep->name)) {
2193 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2197 if (dep->fid.vnode != 0
2198 && (smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)
2200 && smb_V3MatchMask(shortName, maskp,
2201 CM_FLAG_CASEFOLD)))) {
2202 /* finally check if this name will fit */
2204 /* standard dir entry stuff */
2205 if (infoLevel < 0x101)
2206 ohbytes = 23; /* pre-NT */
2207 else if (infoLevel == 0x103)
2208 ohbytes = 12; /* NT names only */
2210 ohbytes = 64; /* NT */
2212 if (infoLevel == 0x104)
2213 ohbytes += 26; /* Short name & length */
2215 if (searchFlags & 4) {
2216 ohbytes += 4; /* if resume key required */
2220 && infoLevel != 0x101
2221 && infoLevel != 0x103)
2222 ohbytes += 4; /* EASIZE */
2224 /* add header to name & term. null */
2225 orbytes = onbytes + ohbytes + 1;
2227 /* now, we round up the record to a 4 byte alignment,
2228 * and we make sure that we have enough room here for
2229 * even the aligned version (so we don't have to worry
2230 * about an * overflow when we pad things out below).
2231 * That's the reason for the alignment arithmetic below.
2233 if (infoLevel >= 0x101)
2234 align = (4 - (orbytes & 3)) & 3;
2237 if (orbytes + bytesInBuffer + align > maxReturnData)
2240 /* this is one of the entries to use: it is not deleted
2241 * and it matches the star pattern we're looking for.
2242 * Put out the name, preceded by its length.
2244 /* First zero everything else */
2245 memset(origOp, 0, ohbytes);
2247 if (infoLevel <= 0x101)
2248 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2249 else if (infoLevel == 0x103)
2250 *((u_long *)(op + 8)) = onbytes;
2252 *((u_long *)(op + 60)) = onbytes;
2253 strcpy(origOp+ohbytes, dep->name);
2255 /* Short name if requested and needed */
2256 if (infoLevel == 0x104) {
2257 if (NeedShortName) {
2258 strcpy(op + 70, shortName);
2259 *(op + 68) = shortNameEnd - shortName;
2263 /* now, adjust the # of entries copied */
2266 /* NextEntryOffset and FileIndex */
2267 if (infoLevel >= 101) {
2268 int entryOffset = orbytes + align;
2269 *((u_long *)op) = entryOffset;
2270 *((u_long *)(op+4)) = nextEntryCookie;
2273 /* now we emit the attribute. This is tricky, since
2274 * we need to really stat the file to find out what
2275 * type of entry we've got. Right now, we're copying
2276 * out data from * a buffer, while holding the scp
2277 * locked, so it isn't really convenient to stat
2278 * something now. We'll put in a place holder
2279 * now, and make a second pass before returning this
2280 * to get the real attributes. So, we just skip the
2281 * data for now, and adjust it later. We allocate a
2282 * patch record to make it easy to find this point
2283 * later. The replay will happen at a time when it is
2284 * safe to unlock the directory.
2286 if (infoLevel != 0x103) {
2287 curPatchp = malloc(sizeof(*curPatchp));
2288 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2290 curPatchp->dptr = op;
2291 if (infoLevel >= 0x101)
2292 curPatchp->dptr += 8;
2293 curPatchp->fid.cell = scp->fid.cell;
2294 curPatchp->fid.volume = scp->fid.volume;
2295 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2296 curPatchp->fid.unique = ntohl(dep->fid.unique);
2299 if (searchFlags & 4)
2300 /* put out resume key */
2301 *((u_long *)origOp) = nextEntryCookie;
2303 /* Adjust byte ptr and count */
2304 origOp += orbytes; /* skip entire record */
2305 bytesInBuffer += orbytes;
2307 /* and pad the record out */
2308 while (--align >= 0) {
2313 } /* if we're including this name */
2316 /* and adjust curOffset to be where the new cookie is */
2317 thyper.HighPart = 0;
2318 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2319 curOffset = LargeIntegerAdd(thyper, curOffset);
2320 } /* while copying data for dir listing */
2322 /* release the mutex */
2323 lock_ReleaseMutex(&scp->mx);
2324 if (bufferp) buf_Release(bufferp);
2326 /* apply and free last set of patches; if not doing a star match, this
2327 * will be empty, but better safe (and freeing everything) than sorry.
2329 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2332 /* now put out the final parameters */
2333 if (returnedNames == 0) eos = 1;
2334 if (p->opcode == 1) {
2336 outp->parmsp[0] = (unsigned short) dsp->cookie;
2337 outp->parmsp[1] = returnedNames;
2338 outp->parmsp[2] = eos;
2339 outp->parmsp[3] = 0; /* nothing wrong with EAS */
2340 outp->parmsp[4] = 0; /* don't need last name to continue
2341 * search, cookie is enough. Normally,
2342 * this is the offset of the file name
2343 * of the last entry returned.
2345 outp->totalParms = 10; /* in bytes */
2349 outp->parmsp[0] = returnedNames;
2350 outp->parmsp[1] = eos;
2351 outp->parmsp[2] = 0; /* EAS error */
2352 outp->parmsp[3] = 0; /* last name, as above */
2353 outp->totalParms = 8; /* in bytes */
2356 /* return # of bytes in the buffer */
2357 outp->totalData = bytesInBuffer;
2359 osi_Log2(afsd_logp, "T2 search dir done, %d names, code %d",
2360 returnedNames, code);
2362 /* Return error code if unsuccessful on first request */
2363 if (code == 0 && p->opcode == 1 && returnedNames == 0)
2364 code = CM_ERROR_NOSUCHFILE;
2366 /* if we're supposed to close the search after this request, or if
2367 * we're supposed to close the search if we're done, and we're done,
2368 * or if something went wrong, close the search.
2370 if ((searchFlags & 1) || ((searchFlags & 2) && eos)
2371 || code != 0) smb_DeleteDirSearch(dsp);
2373 smb_SendTran2Error(vcp, p, opx, code);
2375 smb_SendTran2Packet(vcp, outp, opx);
2377 smb_FreeTran2Packet(outp);
2378 smb_ReleaseDirSearch(dsp);
2379 cm_ReleaseSCache(scp);
2380 cm_ReleaseUser(userp);
2384 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2387 smb_dirSearch_t *dsp;
2389 dirHandle = smb_GetSMBParm(inp, 0);
2391 osi_Log1(afsd_logp, "SMB3 find close handle %d", dirHandle);
2393 dsp = smb_FindDirSearch(dirHandle);
2396 return CM_ERROR_BADFD;
2398 /* otherwise, we have an FD to destroy */
2399 smb_DeleteDirSearch(dsp);
2400 smb_ReleaseDirSearch(dsp);
2402 /* and return results */
2403 smb_SetSMBDataLength(outp, 0);
2408 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2410 smb_SetSMBDataLength(outp, 0);
2414 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2421 cm_scache_t *dscp; /* dir we're dealing with */
2422 cm_scache_t *scp; /* file we're creating */
2424 int initialModeBits;
2434 int parmSlot; /* which parm we're dealing with */
2442 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
2443 openFun = smb_GetSMBParm(inp, 8); /* open function */
2444 excl = ((openFun & 3) == 0);
2445 trunc = ((openFun & 3) == 2); /* truncate it */
2446 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2447 openAction = 0; /* tracks what we did */
2449 attributes = smb_GetSMBParm(inp, 5);
2450 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2452 /* compute initial mode bits based on read-only flag in attributes */
2453 initialModeBits = 0666;
2454 if (attributes & 1) initialModeBits &= ~0222;
2456 pathp = smb_GetSMBData(inp, NULL);
2458 spacep = inp->spacep;
2459 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2461 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2462 /* special case magic file name for receiving IOCTL requests
2463 * (since IOCTL calls themselves aren't getting through).
2465 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2466 smb_SetupIoctlFid(fidp, spacep);
2468 /* set inp->fid so that later read calls in same msg can find fid */
2469 inp->fid = fidp->fid;
2471 /* copy out remainder of the parms */
2473 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2475 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2476 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
2477 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2478 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
2479 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2480 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2481 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2482 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2484 /* and the final "always present" stuff */
2485 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2486 /* next write out the "unique" ID */
2487 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2488 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2489 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2490 smb_SetSMBDataLength(outp, 0);
2492 /* and clean up fid reference */
2493 smb_ReleaseFID(fidp);
2497 userp = smb_GetUser(vcp, inp);
2500 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2501 code = cm_NameI(cm_rootSCachep, pathp,
2502 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2503 userp, tidPathp, &req, &scp);
2505 code = cm_NameI(cm_rootSCachep, spacep->data,
2506 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2507 userp, tidPathp, &req, &dscp);
2510 cm_ReleaseUser(userp);
2514 /* otherwise, scp points to the parent directory. Do a lookup,
2515 * and truncate the file if we find it, otherwise we create the
2518 if (!lastNamep) lastNamep = pathp;
2520 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2522 if (code && code != CM_ERROR_NOSUCHFILE) {
2523 cm_ReleaseSCache(dscp);
2524 cm_ReleaseUser(userp);
2529 /* if we get here, if code is 0, the file exists and is represented by
2530 * scp. Otherwise, we have to create it. The dir may be represented
2531 * by dscp, or we may have found the file directly. If code is non-zero,
2535 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2537 if (dscp) cm_ReleaseSCache(dscp);
2538 cm_ReleaseSCache(scp);
2539 cm_ReleaseUser(userp);
2544 /* oops, file shouldn't be there */
2545 if (dscp) cm_ReleaseSCache(dscp);
2546 cm_ReleaseSCache(scp);
2547 cm_ReleaseUser(userp);
2548 return CM_ERROR_EXISTS;
2552 setAttr.mask = CM_ATTRMASK_LENGTH;
2553 setAttr.length.LowPart = 0;
2554 setAttr.length.HighPart = 0;
2555 code = cm_SetAttr(scp, &setAttr, userp, &req);
2556 openAction = 3; /* truncated existing file */
2558 else openAction = 1; /* found existing file */
2560 else if (!(openFun & 0x10)) {
2561 /* don't create if not found */
2562 if (dscp) cm_ReleaseSCache(dscp);
2563 cm_ReleaseUser(userp);
2564 return CM_ERROR_NOSUCHFILE;
2567 osi_assert(dscp != NULL);
2568 osi_Log1(afsd_logp, "smb_ReceiveV3OpenX creating file %s",
2569 osi_LogSaveString(afsd_logp, lastNamep));
2570 openAction = 2; /* created file */
2571 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2572 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2573 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2575 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2576 smb_NotifyChange(FILE_ACTION_ADDED,
2577 FILE_NOTIFY_CHANGE_FILE_NAME,
2578 dscp, lastNamep, NULL, TRUE);
2579 if (!excl && code == CM_ERROR_EXISTS) {
2580 /* not an exclusive create, and someone else tried
2581 * creating it already, then we open it anyway. We
2582 * don't bother retrying after this, since if this next
2583 * fails, that means that the file was deleted after we
2584 * started this call.
2586 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2590 setAttr.mask = CM_ATTRMASK_LENGTH;
2591 setAttr.length.LowPart = 0;
2592 setAttr.length.HighPart = 0;
2593 code = cm_SetAttr(scp, &setAttr, userp,
2596 } /* lookup succeeded */
2600 /* we don't need this any longer */
2601 if (dscp) cm_ReleaseSCache(dscp);
2604 /* something went wrong creating or truncating the file */
2605 if (scp) cm_ReleaseSCache(scp);
2606 cm_ReleaseUser(userp);
2610 /* make sure we're about to open a file */
2611 if (scp->fileType != CM_SCACHETYPE_FILE) {
2612 cm_ReleaseSCache(scp);
2613 cm_ReleaseUser(userp);
2614 return CM_ERROR_ISDIR;
2617 /* now all we have to do is open the file itself */
2618 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2621 /* save a pointer to the vnode */
2624 /* compute open mode */
2625 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2626 if (openMode == 1 || openMode == 2)
2627 fidp->flags |= SMB_FID_OPENWRITE;
2629 smb_ReleaseFID(fidp);
2631 cm_Open(scp, 0, userp);
2633 /* set inp->fid so that later read calls in same msg can find fid */
2634 inp->fid = fidp->fid;
2636 /* copy out remainder of the parms */
2638 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2639 lock_ObtainMutex(&scp->mx);
2641 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2642 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2643 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2644 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2645 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2646 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2647 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2648 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2649 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2651 /* and the final "always present" stuff */
2652 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2653 /* next write out the "unique" ID */
2654 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2655 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2656 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2657 lock_ReleaseMutex(&scp->mx);
2658 smb_SetSMBDataLength(outp, 0);
2660 osi_Log1(afsd_logp, "SMB OpenX opening fid %d", fidp->fid);
2662 cm_ReleaseUser(userp);
2663 /* leave scp held since we put it in fidp->scp */
2667 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2674 unsigned char LockType;
2675 unsigned short NumberOfUnlocks, NumberOfLocks;
2676 unsigned long Timeout;
2678 LARGE_INTEGER LOffset, LLength;
2679 smb_waitingLock_t *waitingLock;
2686 fid = smb_GetSMBParm(inp, 2);
2687 fid = smb_ChainFID(fid, inp);
2689 fidp = smb_FindFID(vcp, fid, 0);
2690 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2691 return CM_ERROR_BADFD;
2693 /* set inp->fid so that later read calls in same msg can find fid */
2696 userp = smb_GetUser(vcp, inp);
2700 lock_ObtainMutex(&scp->mx);
2701 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2702 CM_SCACHESYNC_NEEDCALLBACK
2703 | CM_SCACHESYNC_GETSTATUS
2704 | CM_SCACHESYNC_LOCK);
2705 if (code) goto doneSync;
2707 LockType = smb_GetSMBParm(inp, 3) & 0xff;
2708 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2709 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2710 NumberOfLocks = smb_GetSMBParm(inp, 7);
2712 op = smb_GetSMBData(inp, NULL);
2714 for (i=0; i<NumberOfUnlocks; i++) {
2715 if (LockType & 0x10) {
2717 LOffset.HighPart = *((LONG *)(op + 4));
2718 LOffset.LowPart = *((DWORD *)(op + 8));
2719 LLength.HighPart = *((LONG *)(op + 12));
2720 LLength.LowPart = *((DWORD *)(op + 16));
2724 /* Not Large Files */
2725 LOffset.HighPart = 0;
2726 LOffset.LowPart = *((DWORD *)(op + 2));
2727 LLength.HighPart = 0;
2728 LLength.LowPart = *((DWORD *)(op + 6));
2731 if (LargeIntegerNotEqualToZero(LOffset))
2733 /* Do not check length -- length check done in cm_Unlock */
2735 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2736 if (code) goto done;
2739 for (i=0; i<NumberOfLocks; i++) {
2740 if (LockType & 0x10) {
2742 LOffset.HighPart = *((LONG *)(op + 4));
2743 LOffset.LowPart = *((DWORD *)(op + 8));
2744 LLength.HighPart = *((LONG *)(op + 12));
2745 LLength.LowPart = *((DWORD *)(op + 16));
2749 /* Not Large Files */
2750 LOffset.HighPart = 0;
2751 LOffset.LowPart = *((DWORD *)(op + 2));
2752 LLength.HighPart = 0;
2753 LLength.LowPart = *((DWORD *)(op + 6));
2756 if (LargeIntegerNotEqualToZero(LOffset))
2758 if (LargeIntegerLessThan(LOffset, scp->length))
2761 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2762 userp, &req, &lockp);
2763 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2764 /* Put on waiting list */
2765 waitingLock = malloc(sizeof(smb_waitingLock_t));
2766 waitingLock->vcp = vcp;
2767 waitingLock->inp = smb_CopyPacket(inp);
2768 waitingLock->outp = smb_CopyPacket(outp);
2769 waitingLock->timeRemaining = Timeout;
2770 waitingLock->lockp = lockp;
2771 lock_ObtainWrite(&smb_globalLock);
2772 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2774 osi_Wakeup((long) &smb_allWaitingLocks);
2775 lock_ReleaseWrite(&smb_globalLock);
2776 /* don't send reply immediately */
2777 outp->flags |= SMB_PACKETFLAG_NOSEND;
2783 /* release any locks acquired before the failure */
2786 smb_SetSMBDataLength(outp, 0);
2788 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2790 lock_ReleaseMutex(&scp->mx);
2791 cm_ReleaseUser(userp);
2792 smb_ReleaseFID(fidp);
2797 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2809 fid = smb_GetSMBParm(inp, 0);
2810 fid = smb_ChainFID(fid, inp);
2812 fidp = smb_FindFID(vcp, fid, 0);
2813 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2814 return CM_ERROR_BADFD;
2817 userp = smb_GetUser(vcp, inp);
2821 /* otherwise, stat the file */
2822 lock_ObtainMutex(&scp->mx);
2823 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2824 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2825 if (code) goto done;
2827 /* decode times. We need a search time, but the response to this
2828 * call provides the date first, not the time, as returned in the
2829 * searchTime variable. So we take the high-order bits first.
2831 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2832 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
2833 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2834 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
2835 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2836 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
2837 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2839 /* now handle file size and allocation size */
2840 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
2841 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2842 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
2843 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2845 /* file attribute */
2846 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2848 /* and finalize stuff */
2849 smb_SetSMBDataLength(outp, 0);
2853 lock_ReleaseMutex(&scp->mx);
2854 cm_ReleaseUser(userp);
2855 smb_ReleaseFID(fidp);
2859 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2873 fid = smb_GetSMBParm(inp, 0);
2874 fid = smb_ChainFID(fid, inp);
2876 fidp = smb_FindFID(vcp, fid, 0);
2877 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2878 return CM_ERROR_BADFD;
2881 userp = smb_GetUser(vcp, inp);
2885 /* now prepare to call cm_setattr. This message only sets various times,
2886 * and AFS only implements mtime, and we'll set the mtime if that's
2887 * requested. The others we'll ignore.
2889 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
2891 if (searchTime != 0) {
2892 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
2893 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
2894 attrs.clientModTime = unixTime;
2895 code = cm_SetAttr(scp, &attrs, userp, &req);
2899 cm_ReleaseUser(userp);
2900 smb_ReleaseFID(fidp);
2905 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2908 long count, finalCount;
2915 fd = smb_GetSMBParm(inp, 2);
2916 count = smb_GetSMBParm(inp, 5);
2917 offset.HighPart = 0; /* too bad */
2918 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
2920 osi_Log3(afsd_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
2921 fd, offset.LowPart, count);
2923 fd = smb_ChainFID(fd, inp);
2924 fidp = smb_FindFID(vcp, fd, 0);
2926 return CM_ERROR_BADFD;
2928 /* set inp->fid so that later read calls in same msg can find fid */
2931 if (fidp->flags & SMB_FID_IOCTL) {
2932 return smb_IoctlV3Read(fidp, vcp, inp, outp);
2935 userp = smb_GetUser(vcp, inp);
2937 /* 0 and 1 are reserved for request chaining, were setup by our caller,
2938 * and will be further filled in after we return.
2940 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
2941 smb_SetSMBParm(outp, 3, 0); /* resvd */
2942 smb_SetSMBParm(outp, 4, 0); /* resvd */
2943 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
2944 /* fill in #6 when we have all the parameters' space reserved */
2945 smb_SetSMBParm(outp, 7, 0); /* resv'd */
2946 smb_SetSMBParm(outp, 8, 0); /* resv'd */
2947 smb_SetSMBParm(outp, 9, 0); /* resv'd */
2948 smb_SetSMBParm(outp, 10, 0); /* resv'd */
2949 smb_SetSMBParm(outp, 11, 0); /* reserved */
2951 /* get op ptr after putting in the parms, since otherwise we don't
2952 * know where the data really is.
2954 op = smb_GetSMBData(outp, NULL);
2956 /* now fill in offset from start of SMB header to first data byte (to op) */
2957 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
2959 /* set the packet data length the count of the # of bytes */
2960 smb_SetSMBDataLength(outp, count);
2962 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
2964 /* fix some things up */
2965 smb_SetSMBParm(outp, 5, finalCount);
2966 smb_SetSMBDataLength(outp, finalCount);
2968 smb_ReleaseFID(fidp);
2970 cm_ReleaseUser(userp);
2975 * Values for createDisp, copied from NTDDK.H
2977 * FILE_SUPERSEDE 0 (???)
2978 * FILE_OPEN 1 (open)
2979 * FILE_CREATE 2 (exclusive)
2980 * FILE_OPEN_IF 3 (non-exclusive)
2981 * FILE_OVERWRITE 4 (open & truncate, but do not create)
2982 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
2985 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2987 char *pathp, *realPathp;
2991 cm_scache_t *dscp; /* parent dir */
2992 cm_scache_t *scp; /* file to create or open */
2995 unsigned short nameLength;
2997 unsigned int requestOpLock;
2998 unsigned int requestBatchOpLock;
2999 unsigned int mustBeDir;
3001 unsigned int desiredAccess;
3002 unsigned int extAttributes;
3003 unsigned int createDisp;
3004 unsigned int createOptions;
3005 int initialModeBits;
3006 unsigned short baseFid;
3007 smb_fid_t *baseFidp;
3009 cm_scache_t *baseDirp;
3010 unsigned short openAction;
3024 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3025 flags = smb_GetSMBOffsetParm(inp, 3, 1)
3026 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3027 requestOpLock = flags & 0x02;
3028 requestBatchOpLock = flags & 0x04;
3029 mustBeDir = flags & 0x08;
3032 * Why all of a sudden 32-bit FID?
3033 * We will reject all bits higher than 16.
3035 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3036 return CM_ERROR_INVAL;
3037 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3038 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3039 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3040 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3041 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3042 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3043 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3044 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3045 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3047 /* mustBeDir is never set; createOptions directory bit seems to be
3050 if (createOptions & 1)
3052 else if (createOptions & 0x40)
3058 * compute initial mode bits based on read-only flag in
3059 * extended attributes
3061 initialModeBits = 0666;
3062 if (extAttributes & 1) initialModeBits &= ~0222;
3064 pathp = smb_GetSMBData(inp, NULL);
3065 /* Sometimes path is not null-terminated, so we make a copy. */
3066 realPathp = malloc(nameLength+1);
3067 memcpy(realPathp, pathp, nameLength);
3068 realPathp[nameLength] = 0;
3070 spacep = inp->spacep;
3071 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3073 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3074 /* special case magic file name for receiving IOCTL requests
3075 * (since IOCTL calls themselves aren't getting through).
3077 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3078 smb_SetupIoctlFid(fidp, spacep);
3080 /* set inp->fid so that later read calls in same msg can find fid */
3081 inp->fid = fidp->fid;
3085 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3086 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3087 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3089 memset(&ft, 0, sizeof(ft));
3090 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3091 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3092 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3093 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3094 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3095 sz.HighPart = 0x7fff; sz.LowPart = 0;
3096 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3097 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3098 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3099 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3100 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
3101 smb_SetSMBDataLength(outp, 0);
3103 /* clean up fid reference */
3104 smb_ReleaseFID(fidp);
3109 userp = smb_GetUser(vcp, inp);
3112 baseDirp = cm_rootSCachep;
3113 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3116 baseFidp = smb_FindFID(vcp, baseFid, 0);
3117 baseDirp = baseFidp->scp;
3121 /* compute open mode */
3123 if (desiredAccess & DELETE)
3124 fidflags |= SMB_FID_OPENDELETE;
3125 if (desiredAccess & AFS_ACCESS_READ)
3126 fidflags |= SMB_FID_OPENREAD;
3127 if (desiredAccess & AFS_ACCESS_WRITE)
3128 fidflags |= SMB_FID_OPENWRITE;
3132 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3133 userp, tidPathp, &req, &scp);
3134 if (code == 0) foundscp = TRUE;
3136 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3137 /* look up parent directory */
3138 code = cm_NameI(baseDirp, spacep->data,
3139 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3140 userp, tidPathp, &req, &dscp);
3142 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3145 cm_ReleaseUser(userp);
3150 if (!lastNamep) lastNamep = realPathp;
3153 if (!smb_IsLegalFilename(lastNamep))
3154 return CM_ERROR_BADNTFILENAME;
3157 code = cm_Lookup(dscp, lastNamep,
3158 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3160 if (code && code != CM_ERROR_NOSUCHFILE) {
3161 cm_ReleaseSCache(dscp);
3162 cm_ReleaseUser(userp);
3169 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3172 /* if we get here, if code is 0, the file exists and is represented by
3173 * scp. Otherwise, we have to create it. The dir may be represented
3174 * by dscp, or we may have found the file directly. If code is non-zero,
3178 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3181 if (dscp) cm_ReleaseSCache(dscp);
3182 cm_ReleaseSCache(scp);
3183 cm_ReleaseUser(userp);
3188 if (createDisp == 2) {
3189 /* oops, file shouldn't be there */
3190 if (dscp) cm_ReleaseSCache(dscp);
3191 cm_ReleaseSCache(scp);
3192 cm_ReleaseUser(userp);
3194 return CM_ERROR_EXISTS;
3198 || createDisp == 5) {
3199 setAttr.mask = CM_ATTRMASK_LENGTH;
3200 setAttr.length.LowPart = 0;
3201 setAttr.length.HighPart = 0;
3202 code = cm_SetAttr(scp, &setAttr, userp, &req);
3203 openAction = 3; /* truncated existing file */
3205 else openAction = 1; /* found existing file */
3207 else if (createDisp == 1 || createDisp == 4) {
3208 /* don't create if not found */
3209 if (dscp) cm_ReleaseSCache(dscp);
3210 cm_ReleaseUser(userp);
3212 return CM_ERROR_NOSUCHFILE;
3214 else if (realDirFlag == 0 || realDirFlag == -1) {
3215 osi_assert(dscp != NULL);
3216 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating file %s",
3217 osi_LogSaveString(afsd_logp, lastNamep));
3218 openAction = 2; /* created file */
3219 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3220 setAttr.clientModTime = time(NULL);
3221 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3223 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3224 smb_NotifyChange(FILE_ACTION_ADDED,
3225 FILE_NOTIFY_CHANGE_FILE_NAME,
3226 dscp, lastNamep, NULL, TRUE);
3227 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3228 /* Not an exclusive create, and someone else tried
3229 * creating it already, then we open it anyway. We
3230 * don't bother retrying after this, since if this next
3231 * fails, that means that the file was deleted after we
3232 * started this call.
3234 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3237 if (createDisp == 5) {
3238 setAttr.mask = CM_ATTRMASK_LENGTH;
3239 setAttr.length.LowPart = 0;
3240 setAttr.length.HighPart = 0;
3241 code = cm_SetAttr(scp, &setAttr, userp,
3244 } /* lookup succeeded */
3248 /* create directory */
3249 osi_assert(dscp != NULL);
3250 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating directory %s",
3251 osi_LogSaveString(afsd_logp, lastNamep));
3252 openAction = 2; /* created directory */
3253 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3254 setAttr.clientModTime = time(NULL);
3255 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3256 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3257 smb_NotifyChange(FILE_ACTION_ADDED,
3258 FILE_NOTIFY_CHANGE_DIR_NAME,
3259 dscp, lastNamep, NULL, TRUE);
3261 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3262 /* Not an exclusive create, and someone else tried
3263 * creating it already, then we open it anyway. We
3264 * don't bother retrying after this, since if this next
3265 * fails, that means that the file was deleted after we
3266 * started this call.
3268 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3274 /* something went wrong creating or truncating the file */
3275 if (scp) cm_ReleaseSCache(scp);
3276 cm_ReleaseUser(userp);
3281 /* make sure we have file vs. dir right */
3282 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3283 cm_ReleaseSCache(scp);
3284 cm_ReleaseUser(userp);
3286 return CM_ERROR_ISDIR;
3288 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3289 cm_ReleaseSCache(scp);
3290 cm_ReleaseUser(userp);
3292 return CM_ERROR_NOTDIR;
3295 /* open the file itself */
3296 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3298 /* save a pointer to the vnode */
3301 fidp->flags = fidflags;
3303 /* save parent dir and pathname for delete or change notification */
3304 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3305 fidp->flags |= SMB_FID_NTOPEN;
3306 fidp->NTopen_dscp = dscp;
3307 cm_HoldSCache(dscp);
3308 fidp->NTopen_pathp = strdup(lastNamep);
3310 fidp->NTopen_wholepathp = realPathp;
3312 /* we don't need this any longer */
3313 if (dscp) cm_ReleaseSCache(dscp);
3314 cm_Open(scp, 0, userp);
3316 /* set inp->fid so that later read calls in same msg can find fid */
3317 inp->fid = fidp->fid;
3321 lock_ObtainMutex(&scp->mx);
3322 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3323 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3324 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3325 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3326 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3327 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3328 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3329 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3330 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3332 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3333 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3334 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3335 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3336 smb_SetSMBParmByte(outp, parmSlot,
3337 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3338 lock_ReleaseMutex(&scp->mx);
3339 smb_SetSMBDataLength(outp, 0);
3341 osi_Log2(afsd_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3342 osi_LogSaveString(afsd_logp, realPathp));
3344 smb_ReleaseFID(fidp);
3346 cm_ReleaseUser(userp);
3348 /* leave scp held since we put it in fidp->scp */
3353 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3354 * Instead, ultimately, would like to use a subroutine for common code.
3356 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3358 char *pathp, *realPathp;
3362 cm_scache_t *dscp; /* parent dir */
3363 cm_scache_t *scp; /* file to create or open */
3366 unsigned long nameLength;
3368 unsigned int requestOpLock;
3369 unsigned int requestBatchOpLock;
3370 unsigned int mustBeDir;
3372 unsigned int desiredAccess;
3373 unsigned int extAttributes;
3374 unsigned int createDisp;
3375 unsigned int createOptions;
3376 int initialModeBits;
3377 unsigned short baseFid;
3378 smb_fid_t *baseFidp;
3380 cm_scache_t *baseDirp;
3381 unsigned short openAction;
3387 int parmOffset, dataOffset;
3398 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3399 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3400 parmp = inp->data + parmOffset;
3401 lparmp = (ULONG *) parmp;
3404 requestOpLock = flags & 0x02;
3405 requestBatchOpLock = flags & 0x04;
3406 mustBeDir = flags & 0x08;
3408 * Why all of a sudden 32-bit FID?
3409 * We will reject all bits higher than 16.
3411 if (lparmp[1] & 0xFFFF0000)
3412 return CM_ERROR_INVAL;
3413 baseFid = (unsigned short)lparmp[1];
3414 desiredAccess = lparmp[2];
3415 extAttributes = lparmp[5];
3416 createDisp = lparmp[7];
3417 createOptions = lparmp[8];
3418 nameLength = lparmp[11];
3420 /* mustBeDir is never set; createOptions directory bit seems to be
3423 if (createOptions & 1)
3425 else if (createOptions & 0x40)
3431 * compute initial mode bits based on read-only flag in
3432 * extended attributes
3434 initialModeBits = 0666;
3435 if (extAttributes & 1) initialModeBits &= ~0222;
3437 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3438 /* Sometimes path is not null-terminated, so we make a copy. */
3439 realPathp = malloc(nameLength+1);
3440 memcpy(realPathp, pathp, nameLength);
3441 realPathp[nameLength] = 0;
3443 spacep = cm_GetSpace();
3444 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3447 * Nothing here to handle SMB_IOCTL_FILENAME.
3448 * Will add it if necessary.
3451 userp = smb_GetUser(vcp, inp);
3454 baseDirp = cm_rootSCachep;
3455 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3458 baseFidp = smb_FindFID(vcp, baseFid, 0);
3459 baseDirp = baseFidp->scp;
3463 /* compute open mode */
3465 if (desiredAccess & DELETE)
3466 fidflags |= SMB_FID_OPENDELETE;
3467 if (desiredAccess & AFS_ACCESS_READ)
3468 fidflags |= SMB_FID_OPENREAD;
3469 if (desiredAccess & AFS_ACCESS_WRITE)
3470 fidflags |= SMB_FID_OPENWRITE;
3474 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3475 userp, tidPathp, &req, &scp);
3476 if (code == 0) foundscp = TRUE;
3478 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3479 /* look up parent directory */
3480 code = cm_NameI(baseDirp, spacep->data,
3481 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3482 userp, tidPathp, &req, &dscp);
3483 cm_FreeSpace(spacep);
3485 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3488 cm_ReleaseUser(userp);
3493 if (!lastNamep) lastNamep = realPathp;
3496 if (!smb_IsLegalFilename(lastNamep))
3497 return CM_ERROR_BADNTFILENAME;
3500 code = cm_Lookup(dscp, lastNamep,
3501 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3503 if (code && code != CM_ERROR_NOSUCHFILE) {
3504 cm_ReleaseSCache(dscp);
3505 cm_ReleaseUser(userp);
3512 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3513 cm_FreeSpace(spacep);
3516 /* if we get here, if code is 0, the file exists and is represented by
3517 * scp. Otherwise, we have to create it. The dir may be represented
3518 * by dscp, or we may have found the file directly. If code is non-zero,
3522 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3525 if (dscp) cm_ReleaseSCache(dscp);
3526 cm_ReleaseSCache(scp);
3527 cm_ReleaseUser(userp);
3532 if (createDisp == 2) {
3533 /* oops, file shouldn't be there */
3534 if (dscp) cm_ReleaseSCache(dscp);
3535 cm_ReleaseSCache(scp);
3536 cm_ReleaseUser(userp);
3538 return CM_ERROR_EXISTS;
3542 || createDisp == 5) {
3543 setAttr.mask = CM_ATTRMASK_LENGTH;
3544 setAttr.length.LowPart = 0;
3545 setAttr.length.HighPart = 0;
3546 code = cm_SetAttr(scp, &setAttr, userp, &req);
3547 openAction = 3; /* truncated existing file */
3549 else openAction = 1; /* found existing file */
3551 else if (createDisp == 1 || createDisp == 4) {
3552 /* don't create if not found */
3553 if (dscp) cm_ReleaseSCache(dscp);
3554 cm_ReleaseUser(userp);
3556 return CM_ERROR_NOSUCHFILE;
3558 else if (realDirFlag == 0 || realDirFlag == -1) {
3559 osi_assert(dscp != NULL);
3560 osi_Log1(afsd_logp, "smb_ReceiveNTTranCreate creating file %s",
3561 osi_LogSaveString(afsd_logp, lastNamep));
3562 openAction = 2; /* created file */
3563 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3564 setAttr.clientModTime = time(NULL);
3565 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3567 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3568 smb_NotifyChange(FILE_ACTION_ADDED,
3569 FILE_NOTIFY_CHANGE_FILE_NAME,
3570 dscp, lastNamep, NULL, TRUE);
3571 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3572 /* Not an exclusive create, and someone else tried
3573 * creating it already, then we open it anyway. We
3574 * don't bother retrying after this, since if this next
3575 * fails, that means that the file was deleted after we
3576 * started this call.
3578 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3581 if (createDisp == 5) {
3582 setAttr.mask = CM_ATTRMASK_LENGTH;
3583 setAttr.length.LowPart = 0;
3584 setAttr.length.HighPart = 0;
3585 code = cm_SetAttr(scp, &setAttr, userp,
3588 } /* lookup succeeded */
3592 /* create directory */
3593 osi_assert(dscp != NULL);
3595 "smb_ReceiveNTTranCreate creating directory %s",
3596 osi_LogSaveString(afsd_logp, lastNamep));
3597 openAction = 2; /* created directory */
3598 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3599 setAttr.clientModTime = time(NULL);
3600 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3601 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3602 smb_NotifyChange(FILE_ACTION_ADDED,
3603 FILE_NOTIFY_CHANGE_DIR_NAME,
3604 dscp, lastNamep, NULL, TRUE);
3606 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3607 /* Not an exclusive create, and someone else tried
3608 * creating it already, then we open it anyway. We
3609 * don't bother retrying after this, since if this next
3610 * fails, that means that the file was deleted after we
3611 * started this call.
3613 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3619 /* something went wrong creating or truncating the file */
3620 if (scp) cm_ReleaseSCache(scp);
3621 cm_ReleaseUser(userp);
3626 /* make sure we have file vs. dir right */
3627 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3628 cm_ReleaseSCache(scp);
3629 cm_ReleaseUser(userp);
3631 return CM_ERROR_ISDIR;
3633 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3634 cm_ReleaseSCache(scp);
3635 cm_ReleaseUser(userp);
3637 return CM_ERROR_NOTDIR;
3640 /* open the file itself */
3641 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3644 /* save a pointer to the vnode */
3647 fidp->flags = fidflags;
3649 /* save parent dir and pathname for deletion or change notification */
3650 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3651 fidp->flags |= SMB_FID_NTOPEN;
3652 fidp->NTopen_dscp = dscp;
3653 cm_HoldSCache(dscp);
3654 fidp->NTopen_pathp = strdup(lastNamep);
3656 fidp->NTopen_wholepathp = realPathp;
3658 /* we don't need this any longer */
3659 if (dscp) cm_ReleaseSCache(dscp);
3661 cm_Open(scp, 0, userp);
3663 /* set inp->fid so that later read calls in same msg can find fid */
3664 inp->fid = fidp->fid;
3667 parmOffset = 8*4 + 39;
3668 parmOffset += 1; /* pad to 4 */
3669 dataOffset = parmOffset + 70;
3673 /* Total Parameter Count */
3674 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3675 /* Total Data Count */
3676 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3677 /* Parameter Count */
3678 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3679 /* Parameter Offset */
3680 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3681 /* Parameter Displacement */
3682 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3684 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3686 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3687 /* Data Displacement */
3688 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3689 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
3690 smb_SetSMBDataLength(outp, 70);
3692 lock_ObtainMutex(&scp->mx);
3693 outData = smb_GetSMBData(outp, NULL);
3694 outData++; /* round to get to parmOffset */
3695 *outData = 0; outData++; /* oplock */
3696 *outData = 0; outData++; /* reserved */
3697 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
3698 *((ULONG *)outData) = openAction; outData += 4;
3699 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
3700 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3701 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
3702 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
3703 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
3704 *((FILETIME *)outData) = ft; outData += 8; /* change time */
3705 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
3706 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
3707 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
3708 *((USHORT *)outData) = 0; outData += 2; /* filetype */
3709 *((USHORT *)outData) = 0; outData += 2; /* dev state */
3710 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
3711 outData += 2; /* is a dir? */
3712 lock_ReleaseMutex(&scp->mx);
3714 osi_Log1(afsd_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
3716 smb_ReleaseFID(fidp);
3718 cm_ReleaseUser(userp);
3720 /* leave scp held since we put it in fidp->scp */
3724 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
3727 smb_packet_t *savedPacketp;
3728 ULONG filter; USHORT fid, watchtree;
3732 filter = smb_GetSMBParm(inp, 19)
3733 | (smb_GetSMBParm(inp, 20) << 16);
3734 fid = smb_GetSMBParm(inp, 21);
3735 watchtree = smb_GetSMBParm(inp, 22) && 0xffff;
3737 savedPacketp = smb_CopyPacket(inp);
3738 savedPacketp->vcp = vcp;
3739 lock_ObtainMutex(&smb_Dir_Watch_Lock);
3740 savedPacketp->nextp = smb_Directory_Watches;
3741 smb_Directory_Watches = savedPacketp;
3742 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
3744 fidp = smb_FindFID(vcp, fid, 0);
3746 osi_Log4(afsd_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
3747 filter, fid, watchtree, osi_LogSaveString(afsd_logp, fidp->NTopen_wholepathp));
3750 lock_ObtainMutex(&scp->mx);
3752 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
3754 scp->flags |= CM_SCACHEFLAG_WATCHED;
3755 lock_ReleaseMutex(&scp->mx);
3756 smb_ReleaseFID(fidp);
3758 outp->flags |= SMB_PACKETFLAG_NOSEND;
3763 unsigned char nullSecurityDesc[36] = {
3764 0x01, /* security descriptor revision */
3765 0x00, /* reserved, should be zero */
3766 0x00, 0x80, /* security descriptor control;
3767 * 0x8000 : self-relative format */
3768 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
3769 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
3770 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
3771 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
3772 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3773 /* "null SID" owner SID */
3774 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
3775 /* "null SID" group SID */
3778 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3780 int parmOffset, parmCount, dataOffset, dataCount;
3788 ULONG securityInformation;
3790 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3791 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3792 parmp = inp->data + parmOffset;
3793 sparmp = (USHORT *) parmp;
3794 lparmp = (ULONG *) parmp;
3797 securityInformation = lparmp[1];
3799 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
3800 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3808 parmOffset = 8*4 + 39;
3809 parmOffset += 1; /* pad to 4 */
3811 dataOffset = parmOffset + parmCount;
3815 /* Total Parameter Count */
3816 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
3817 /* Total Data Count */
3818 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
3819 /* Parameter Count */
3820 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
3821 /* Parameter Offset */
3822 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3823 /* Parameter Displacement */
3824 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3826 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
3828 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3829 /* Data Displacement */
3830 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3831 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
3832 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
3834 outData = smb_GetSMBData(outp, NULL);
3835 outData++; /* round to get to parmOffset */
3836 *((ULONG *)outData) = 36; outData += 4; /* length */
3838 if (maxData >= 36) {
3839 memcpy(outData, nullSecurityDesc, 36);
3843 return CM_ERROR_BUFFERTOOSMALL;
3846 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3848 unsigned short function;
3850 function = smb_GetSMBParm(inp, 18);
3852 osi_Log1(afsd_logp, "SMB NT Transact function %d", function);
3854 /* We can handle long names */
3855 if (vcp->flags & SMB_VCFLAG_USENT)
3856 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3860 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
3862 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
3864 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
3866 default: return CM_ERROR_INVAL;
3871 * smb_NotifyChange -- find relevant change notification messages and
3874 * If we don't know the file name (i.e. a callback break), filename is
3875 * NULL, and we return a zero-length list.
3877 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
3878 cm_scache_t *dscp, char *filename, char *otherFilename,
3879 BOOL isDirectParent)
3881 smb_packet_t *watch, *lastWatch, *nextWatch;
3882 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
3883 char *outData, *oldOutData;
3887 BOOL twoEntries = FALSE;
3888 ULONG otherNameLen, oldParmCount = 0;
3893 /* Get ready for rename within directory */
3894 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
3896 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
3899 lock_ObtainMutex(&smb_Dir_Watch_Lock);
3900 watch = smb_Directory_Watches;
3902 filter = smb_GetSMBParm(watch, 19)
3903 | (smb_GetSMBParm(watch, 20) << 16);
3904 fid = smb_GetSMBParm(watch, 21);
3905 wtree = smb_GetSMBParm(watch, 22) & 0xffff;
3906 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
3907 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
3911 * Strange hack - bug in NT Client and NT Server that we
3914 if (filter == 3 && wtree)
3917 fidp = smb_FindFID(vcp, fid, 0);
3918 if (fidp->scp != dscp
3919 || (filter & notifyFilter) == 0
3920 || (!isDirectParent && !wtree)) {
3921 smb_ReleaseFID(fidp);
3923 watch = watch->nextp;
3926 smb_ReleaseFID(fidp);
3929 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
3930 fid, filter, wtree, osi_LogSaveString(afsd_logp, filename));
3932 nextWatch = watch->nextp;
3933 if (watch == smb_Directory_Watches)
3934 smb_Directory_Watches = nextWatch;
3936 lastWatch->nextp = nextWatch;
3938 /* Turn off WATCHED flag in dscp */
3939 lock_ObtainMutex(&dscp->mx);
3941 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
3943 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
3944 lock_ReleaseMutex(&dscp->mx);
3946 /* Convert to response packet */
3947 ((smb_t *) watch)->reb = 0x80;
3948 ((smb_t *) watch)->wct = 0;
3951 if (filename == NULL)
3954 nameLen = strlen(filename);
3955 parmCount = 3*4 + nameLen*2;
3956 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
3958 otherNameLen = strlen(otherFilename);
3959 oldParmCount = parmCount;
3960 parmCount += 3*4 + otherNameLen*2;
3961 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
3963 if (maxLen < parmCount)
3964 parmCount = 0; /* not enough room */
3966 parmOffset = 8*4 + 39;
3967 parmOffset += 1; /* pad to 4 */
3968 dataOffset = parmOffset + parmCount;
3972 /* Total Parameter Count */
3973 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
3974 /* Total Data Count */
3975 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
3976 /* Parameter Count */
3977 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
3978 /* Parameter Offset */
3979 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
3980 /* Parameter Displacement */
3981 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
3983 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
3985 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
3986 /* Data Displacement */
3987 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
3988 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
3989 smb_SetSMBDataLength(watch, parmCount + 1);
3991 if (parmCount != 0) {
3992 outData = smb_GetSMBData(watch, NULL);
3993 outData++; /* round to get to parmOffset */
3994 oldOutData = outData;
3995 *((DWORD *)outData) = oldParmCount; outData += 4;
3996 /* Next Entry Offset */
3997 *((DWORD *)outData) = action; outData += 4;
3999 *((DWORD *)outData) = nameLen*2; outData += 4;
4000 /* File Name Length */
4001 mbstowcs((WCHAR *)outData, filename, nameLen);
4004 outData = oldOutData + oldParmCount;
4005 *((DWORD *)outData) = 0; outData += 4;
4006 /* Next Entry Offset */
4007 *((DWORD *)outData) = otherAction; outData += 4;
4009 *((DWORD *)outData) = otherNameLen*2;
4010 outData += 4; /* File Name Length */
4011 mbstowcs((WCHAR *)outData, otherFilename,
4012 otherNameLen); /* File Name */
4017 * If filename is null, we don't know the cause of the
4018 * change notification. We return zero data (see above),
4019 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
4020 * (= 0x010C). We set the error code here by hand, without
4021 * modifying wct and bcc.
4023 if (filename == NULL) {
4024 ((smb_t *) watch)->rcls = 0x0C;
4025 ((smb_t *) watch)->reh = 0x01;
4026 ((smb_t *) watch)->errLow = 0;
4027 ((smb_t *) watch)->errHigh = 0;
4028 /* Set NT Status codes flag */
4029 ((smb_t *) watch)->flg2 |= 0x4000;
4032 smb_SendPacket(vcp, watch);
4033 smb_FreePacket(watch);
4036 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4039 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4041 unsigned char *replyWctp;
4042 smb_packet_t *watch, *lastWatch;
4043 USHORT fid, watchtree;
4047 osi_Log0(afsd_logp, "SMB3 receive NT cancel");
4049 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4050 watch = smb_Directory_Watches;
4052 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
4053 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
4054 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
4055 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
4056 if (watch == smb_Directory_Watches)
4057 smb_Directory_Watches = watch->nextp;
4059 lastWatch->nextp = watch->nextp;
4060 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4062 /* Turn off WATCHED flag in scp */
4063 fid = smb_GetSMBParm(watch, 21);
4064 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
4066 fidp = smb_FindFID(vcp, fid, 0);
4068 osi_Log3(afsd_logp, "Cancelling change notification for fid %d wtree %d file %s",
4070 osi_LogSaveString(afsd_logp, fidp->NTopen_wholepathp));
4073 lock_ObtainMutex(&scp->mx);
4075 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4077 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
4078 lock_ReleaseMutex(&scp->mx);
4079 smb_ReleaseFID(fidp);
4081 /* assume STATUS32; return 0xC0000120 (CANCELED) */
4082 replyWctp = watch->wctp;
4086 ((smb_t *)watch)->rcls = 0x20;
4087 ((smb_t *)watch)->reh = 0x1;
4088 ((smb_t *)watch)->errLow = 0;
4089 ((smb_t *)watch)->errHigh = 0xC0;
4090 ((smb_t *)watch)->flg2 |= 0x4000;
4091 smb_SendPacket(vcp, watch);
4092 smb_FreePacket(watch);
4096 watch = watch->nextp;
4098 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4105 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");