2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
28 extern smb_vc_t *dead_vcp;
30 extern osi_hyper_t hzero;
32 smb_packet_t *smb_Directory_Watches = NULL;
33 osi_mutex_t smb_Dir_Watch_Lock;
35 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
37 /* protected by the smb_globalLock */
38 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
40 /* retrieve a held reference to a user structure corresponding to an incoming
42 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
47 uidp = smb_FindUID(vcp, inp->uid, 0);
48 if (!uidp) return NULL;
50 lock_ObtainMutex(&uidp->mx);
53 lock_ReleaseMutex(&uidp->mx);
61 * Return extended attributes.
62 * Right now, we aren't using any of the "new" bits, so this looks exactly
63 * like smb_Attributes() (see smb.c).
65 unsigned long smb_ExtAttributes(cm_scache_t *scp)
69 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
70 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
75 * We used to mark a file RO if it was in an RO volume, but that
76 * turns out to be impolitic in NT. See defect 10007.
79 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
81 if ((scp->unixModeBits & 0222) == 0)
82 attrs |= 1; /* Read-only */
85 attrs = 0x80; /* FILE_ATTRIBUTE_NORMAL */
90 int smb_V3IsStarMask(char *maskp)
95 if (tc == '?' || tc == '*') return 1;
99 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
102 /* skip over null-terminated string */
103 *chainpp = inp + strlen(inp) + 1;
108 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
111 char *usern, *pwd, *pwdx;
112 smb_user_t *uidp, *dead_uidp;
113 unsigned short newUid;
118 /* Check for bad conns */
119 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
120 return CM_ERROR_REMOTECONN;
122 /* For NT LM 0.12 and up, get capabilities */
123 if (vcp->flags & SMB_VCFLAG_USENT) {
124 caps = smb_GetSMBParm(inp, 11);
126 vcp->flags |= SMB_VCFLAG_STATUS32;
127 /* for now, ignore other capability bits */
131 tp = smb_GetSMBData(inp, NULL);
132 if (vcp->flags & SMB_VCFLAG_USENT)
133 pwdx = smb_ParseString(tp, &tp);
134 pwd = smb_ParseString(tp, &tp);
135 usern = smb_ParseString(tp, &tp);
137 /* Create a new UID and cm_user_t structure */
138 userp = cm_NewUser();
139 lock_ObtainMutex(&vcp->mx);
140 newUid = vcp->uidCounter++;
141 lock_ReleaseMutex(&vcp->mx);
143 /* Create a new smb_user_t structure and connect them up */
144 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
145 lock_ObtainMutex(&uidp->mx);
147 uidp->name = strdup(usern);
148 lock_ReleaseMutex(&uidp->mx);
149 smb_ReleaseUID(uidp);
152 dead_uidp = dead_vcp->usersp;
155 && strcmp(dead_uidp->name, usern) == 0)
157 dead_uidp = dead_uidp->nextp;
161 /* transfer tokens from dead vcp */
162 if (dead_vcp && dead_uidp) {
163 cm_user_t *dead_userp;
164 s1 = ", tokens from terminated session";
165 dead_userp = dead_uidp->userp;
166 cm_ResetACLCache(dead_userp);
167 userp->cellInfop = dead_userp->cellInfop;
168 dead_userp->cellInfop = NULL;
172 /* transfer tokens from integrated logon */
173 if (vcp->logonDLLUser) {
174 s1 = ", tokens from integrated logon";
175 cm_ResetACLCache(vcp->logonDLLUser);
176 userp->cellInfop = vcp->logonDLLUser->cellInfop;
177 vcp->logonDLLUser->cellInfop = NULL;
178 vcp->logonDLLUser = NULL;
181 /* transfer tokens for logoff profile upload */
182 if (vcp->justLoggedOut) {
183 cm_user_t *logout_userp;
184 if (GetTickCount() - vcp->logoffTime <
185 1000 * smb_LogoffTransferTimeout
186 && strcmp(vcp->justLoggedOut->name, usern) == 0) {
187 s1 = ", tokens from logoff";
188 logout_userp = vcp->justLoggedOut->userp;
189 cm_ResetACLCache(logout_userp);
190 userp->cellInfop = logout_userp->cellInfop;
191 logout_userp->cellInfop = NULL;
193 vcp->justLoggedOut = NULL;
195 else if (loggedOut) {
196 cm_user_t *logout_userp;
197 if (GetTickCount() - loggedOutTime <
198 1000 * smb_LogoffTransferTimeout
199 && strcmp(loggedOutName, usern) == 0) {
200 s1 = ", tokens from logoff";
201 logout_userp = loggedOutUserp->userp;
202 cm_ResetACLCache(logout_userp);
203 userp->cellInfop = logout_userp->cellInfop;
204 logout_userp->cellInfop = NULL;
206 smb_ReleaseUID(loggedOutUserp);
207 loggedOutUserp = NULL;
209 loggedOutName = NULL;
213 /* Return UID to the client */
214 ((smb_t *)outp)->uid = newUid;
215 /* Also to the next chained message */
216 ((smb_t *)inp)->uid = newUid;
218 osi_Log3(afsd_logp, "SMB3 session setup name %s creating ID %d%s",
219 osi_LogSaveString(afsd_logp, usern), newUid, osi_LogSaveString(afsd_logp, s1));
220 smb_SetSMBParm(outp, 2, 0);
221 smb_SetSMBDataLength(outp, 0);
225 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
229 /* don't get tokens from this VC */
230 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
232 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
234 /* find the tree and free it */
235 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
237 char *s1 = NULL, *s2 = NULL;
239 /* Also, this is not logon session any more */
240 if (uidp->userp == vcp->logonDLLUser) {
241 s1 = ", was logon session";
242 vcp->logonDLLUser = NULL;
245 /* But its tokens might be needed later */
246 if (uidp->userp && !(uidp->userp->flags & CM_USERFLAG_WASLOGON)
247 && smb_LogoffTokenTransfer) {
248 s2 = ", pre-logout effect";
249 vcp->justLoggedOut = uidp;
250 vcp->logoffTime = GetTickCount();
253 if (s2 == NULL) s2 = " ";
254 if (s1 == NULL) {s1 = s2; s2 = " ";}
256 osi_Log4(afsd_logp, "SMB3 user logoffX uid %d name %s%s%s",
258 osi_LogSaveString(afsd_logp, uidp->name),
261 lock_ObtainMutex(&uidp->mx);
262 uidp->flags |= SMB_USERFLAG_DELETE;
264 * it doesn't get deleted right away
265 * because the vcp points to it
267 lock_ReleaseMutex(&uidp->mx);
270 osi_Log0(afsd_logp, "SMB3 user logoffX");
272 smb_SetSMBDataLength(outp, 0);
276 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
279 unsigned short newTid;
289 osi_Log0(afsd_logp, "SMB3 receive tree connect");
291 /* parse input parameters */
292 tp = smb_GetSMBData(inp, NULL);
293 passwordp = smb_ParseString(tp, &tp);
294 pathp = smb_ParseString(tp, &tp);
295 servicep = smb_ParseString(tp, &tp);
297 tp = strrchr(pathp, '\\');
299 return CM_ERROR_BADSMB;
301 strcpy(shareName, tp+1);
303 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0)
304 return CM_ERROR_NOIPC;
306 userp = smb_GetUser(vcp, inp);
308 lock_ObtainMutex(&vcp->mx);
309 newTid = vcp->tidCounter++;
310 lock_ReleaseMutex(&vcp->mx);
312 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
313 shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
315 smb_ReleaseTID(tidp);
316 return CM_ERROR_BADSHARENAME;
318 lock_ObtainMutex(&tidp->mx);
320 tidp->pathname = sharePath;
321 lock_ReleaseMutex(&tidp->mx);
322 smb_ReleaseTID(tidp);
324 if (vcp->flags & SMB_VCFLAG_USENT)
325 smb_SetSMBParm(outp, 2, 0); /* OptionalSupport bits */
327 ((smb_t *)outp)->tid = newTid;
328 ((smb_t *)inp)->tid = newTid;
329 tp = smb_GetSMBData(outp, NULL);
333 smb_SetSMBDataLength(outp, 3);
335 osi_Log1(afsd_logp, "SMB3 tree connect created ID %d", newTid);
339 /* must be called with global tran lock held */
340 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
342 smb_tran2Packet_t *tp;
345 smbp = (smb_t *) inp->data;
346 for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
347 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
353 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
354 int totalParms, int totalData)
356 smb_tran2Packet_t *tp;
359 smbp = (smb_t *) inp->data;
360 tp = malloc(sizeof(*tp));
361 memset(tp, 0, sizeof(*tp));
364 tp->curData = tp->curParms = 0;
365 tp->totalData = totalData;
366 tp->totalParms = totalParms;
371 tp->res[0] = smbp->res[0];
372 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
373 tp->opcode = smb_GetSMBParm(inp, 14);
375 tp->parmsp = malloc(totalParms);
377 tp->datap = malloc(totalData);
378 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
382 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
383 smb_tran2Packet_t *inp, smb_packet_t *outp,
384 int totalParms, int totalData)
386 smb_tran2Packet_t *tp;
387 unsigned short parmOffset;
388 unsigned short dataOffset;
389 unsigned short dataAlign;
391 tp = malloc(sizeof(*tp));
392 memset(tp, 0, sizeof(*tp));
394 tp->curData = tp->curParms = 0;
395 tp->totalData = totalData;
396 tp->totalParms = totalParms;
397 tp->oldTotalParms = totalParms;
402 tp->res[0] = inp->res[0];
403 tp->opcode = inp->opcode;
406 * We calculate where the parameters and data will start.
407 * This calculation must parallel the calculation in
408 * smb_SendTran2Packet.
411 parmOffset = 10*2 + 35;
412 parmOffset++; /* round to even */
413 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
415 dataOffset = parmOffset + totalParms;
416 dataAlign = dataOffset & 2; /* quad-align */
417 dataOffset += dataAlign;
418 tp->datap = outp->data + dataOffset;
423 /* free a tran2 packet; must be called with smb_globalLock held */
424 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
426 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
427 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
436 /* called with a VC, an input packet to respond to, and an error code.
437 * sends an error response.
439 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
440 smb_packet_t *tp, long code)
443 unsigned short errCode;
444 unsigned char errClass;
445 unsigned long NTStatus;
447 if (vcp->flags & SMB_VCFLAG_STATUS32)
448 smb_MapNTError(code, &NTStatus);
450 smb_MapCoreError(code, vcp, &errCode, &errClass);
452 smb_FormatResponsePacket(vcp, NULL, tp);
455 /* We can handle long names */
456 if (vcp->flags & SMB_VCFLAG_USENT)
457 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
459 /* now copy important fields from the tran 2 packet */
460 smbp->com = 0x32; /* tran 2 response */
461 smbp->tid = t2p->tid;
462 smbp->mid = t2p->mid;
463 smbp->pid = t2p->pid;
464 smbp->uid = t2p->uid;
465 smbp->res[0] = t2p->res[0];
466 if (vcp->flags & SMB_VCFLAG_STATUS32) {
467 smbp->rcls = (unsigned char) (NTStatus & 0xff);
468 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
469 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
470 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
471 smbp->flg2 |= 0x4000;
474 smbp->rcls = errClass;
475 smbp->errLow = (unsigned char) (errCode & 0xff);
476 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
480 smb_SendPacket(vcp, tp);
483 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
486 unsigned short parmOffset;
487 unsigned short dataOffset;
488 unsigned short totalLength;
489 unsigned short dataAlign;
492 smb_FormatResponsePacket(vcp, NULL, tp);
495 /* We can handle long names */
496 if (vcp->flags & SMB_VCFLAG_USENT)
497 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
499 /* now copy important fields from the tran 2 packet */
500 smbp->com = 0x32; /* tran 2 response */
501 smbp->tid = t2p->tid;
502 smbp->mid = t2p->mid;
503 smbp->pid = t2p->pid;
504 smbp->uid = t2p->uid;
505 smbp->res[0] = t2p->res[0];
507 totalLength = 1 + t2p->totalData + t2p->totalParms;
509 /* now add the core parameters (tran2 info) to the packet */
510 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
511 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
512 smb_SetSMBParm(tp, 2, 0); /* reserved */
513 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
514 parmOffset = 10*2 + 35; /* parm offset in packet */
515 parmOffset++; /* round to even */
516 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
517 * hdr, bcc and wct */
518 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
519 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
520 dataOffset = parmOffset + t2p->oldTotalParms;
521 dataAlign = dataOffset & 2; /* quad-align */
522 dataOffset += dataAlign;
523 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
524 smb_SetSMBParm(tp, 8, 0); /* data displacement */
525 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
528 datap = smb_GetSMBData(tp, NULL);
529 *datap++ = 0; /* we rounded to even */
531 totalLength += dataAlign;
532 smb_SetSMBDataLength(tp, totalLength);
534 /* next, send the datagram */
535 smb_SendPacket(vcp, tp);
538 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
540 smb_tran2Packet_t *asp;
552 /* We sometimes see 0 word count. What to do? */
553 if (*inp->wctp == 0) {
558 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0");
560 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
561 ptbuf[0] = "Transaction2 word count = 0";
562 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
563 1, inp->ncb_length, ptbuf, inp);
564 DeregisterEventSource(h);
566 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0");
569 smb_SetSMBDataLength(outp, 0);
570 smb_SendPacket(vcp, outp);
574 totalParms = smb_GetSMBParm(inp, 0);
575 totalData = smb_GetSMBParm(inp, 1);
577 firstPacket = (inp->inCom == 0x32);
579 /* find the packet we're reassembling */
580 lock_ObtainWrite(&smb_globalLock);
581 asp = smb_FindTran2Packet(vcp, inp);
583 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
585 lock_ReleaseWrite(&smb_globalLock);
587 /* now merge in this latest packet; start by looking up offsets */
589 parmDisp = dataDisp = 0;
590 parmOffset = smb_GetSMBParm(inp, 10);
591 dataOffset = smb_GetSMBParm(inp, 12);
592 parmCount = smb_GetSMBParm(inp, 9);
593 dataCount = smb_GetSMBParm(inp, 11);
594 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
595 asp->maxReturnData = smb_GetSMBParm(inp, 3);
597 osi_Log3(afsd_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
598 totalData, dataCount, asp->maxReturnData);
601 parmDisp = smb_GetSMBParm(inp, 4);
602 parmOffset = smb_GetSMBParm(inp, 3);
603 dataDisp = smb_GetSMBParm(inp, 7);
604 dataOffset = smb_GetSMBParm(inp, 6);
605 parmCount = smb_GetSMBParm(inp, 2);
606 dataCount = smb_GetSMBParm(inp, 5);
608 osi_Log2(afsd_logp, "SMB3 received T2 aux packet parms %d, data %d",
609 parmCount, dataCount);
612 /* now copy the parms and data */
613 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
614 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
616 /* account for new bytes */
617 asp->curData += dataCount;
618 asp->curParms += parmCount;
620 /* finally, if we're done, remove the packet from the queue and dispatch it */
621 if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
622 /* we've received it all */
623 lock_ObtainWrite(&smb_globalLock);
624 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
625 lock_ReleaseWrite(&smb_globalLock);
627 /* now dispatch it */
628 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
630 /* if an error is returned, we're supposed to send an error packet,
631 * otherwise the dispatched function already did the data sending.
632 * We give dispatched proc the responsibility since it knows how much
636 smb_SendTran2Error(vcp, asp, outp, code);
639 /* free the input tran 2 packet */
640 lock_ObtainWrite(&smb_globalLock);
641 smb_FreeTran2Packet(asp);
642 lock_ReleaseWrite(&smb_globalLock);
644 else if (firstPacket) {
645 /* the first packet in a multi-packet request, we need to send an
646 * ack to get more data.
648 smb_SetSMBDataLength(outp, 0);
649 smb_SendPacket(vcp, outp);
655 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
658 smb_tran2Packet_t *outp;
663 cm_scache_t *dscp; /* dir we're dealing with */
664 cm_scache_t *scp; /* file we're creating */
676 int parmSlot; /* which parm we're dealing with */
685 extraInfo = (p->parmsp[0] & 1); /* return extra info */
686 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
688 openFun = p->parmsp[6]; /* open function */
689 excl = ((openFun & 3) == 0);
690 trunc = ((openFun & 3) == 2); /* truncate it */
691 openMode = (p->parmsp[1] & 0x7);
692 openAction = 0; /* tracks what we did */
694 attributes = p->parmsp[3];
695 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
697 /* compute initial mode bits based on read-only flag in attributes */
698 initialModeBits = 0666;
699 if (attributes & 1) initialModeBits &= ~0222;
701 pathp = (char *) (&p->parmsp[14]);
703 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
705 spacep = cm_GetSpace();
706 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
708 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
709 /* special case magic file name for receiving IOCTL requests
710 * (since IOCTL calls themselves aren't getting through).
712 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
713 smb_SetupIoctlFid(fidp, spacep);
715 /* copy out remainder of the parms */
717 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
719 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
720 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
721 outp->parmsp[parmSlot] = 0; parmSlot++;
722 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
723 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
724 outp->parmsp[parmSlot] = openMode; parmSlot++;
725 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
726 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
728 /* and the final "always present" stuff */
729 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
730 /* next write out the "unique" ID */
731 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
732 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
733 outp->parmsp[parmSlot] = 0; parmSlot++;
734 if (returnEALength) {
735 outp->parmsp[parmSlot] = 0; parmSlot++;
736 outp->parmsp[parmSlot] = 0; parmSlot++;
740 outp->totalParms = parmSlot * 2;
742 smb_SendTran2Packet(vcp, outp, op);
744 smb_FreeTran2Packet(outp);
746 /* and clean up fid reference */
747 smb_ReleaseFID(fidp);
751 userp = smb_GetTran2User(vcp, p);
752 tidPathp = smb_GetTIDPath(vcp, p->tid);
755 code = cm_NameI(cm_rootSCachep, pathp,
756 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
757 userp, tidPathp, &req, &scp);
759 code = cm_NameI(cm_rootSCachep, spacep->data,
760 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
761 userp, tidPathp, &req, &dscp);
762 cm_FreeSpace(spacep);
765 cm_ReleaseUser(userp);
766 smb_FreeTran2Packet(outp);
770 /* otherwise, scp points to the parent directory. Do a lookup,
771 * and truncate the file if we find it, otherwise we create the
774 if (!lastNamep) lastNamep = pathp;
776 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
778 if (code && code != CM_ERROR_NOSUCHFILE) {
779 cm_ReleaseSCache(dscp);
780 cm_ReleaseUser(userp);
781 smb_FreeTran2Packet(outp);
786 cm_FreeSpace(spacep);
789 /* if we get here, if code is 0, the file exists and is represented by
790 * scp. Otherwise, we have to create it.
793 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
795 if (dscp) cm_ReleaseSCache(dscp);
796 cm_ReleaseSCache(scp);
797 cm_ReleaseUser(userp);
798 smb_FreeTran2Packet(outp);
803 /* oops, file shouldn't be there */
804 if (dscp) cm_ReleaseSCache(dscp);
805 cm_ReleaseSCache(scp);
806 cm_ReleaseUser(userp);
807 smb_FreeTran2Packet(outp);
808 return CM_ERROR_EXISTS;
812 setAttr.mask = CM_ATTRMASK_LENGTH;
813 setAttr.length.LowPart = 0;
814 setAttr.length.HighPart = 0;
815 code = cm_SetAttr(scp, &setAttr, userp, &req);
816 openAction = 3; /* truncated existing file */
818 else openAction = 1; /* found existing file */
820 else if (!(openFun & 0x10)) {
821 /* don't create if not found */
822 if (dscp) cm_ReleaseSCache(dscp);
823 osi_assert(scp == NULL);
824 cm_ReleaseUser(userp);
825 smb_FreeTran2Packet(outp);
826 return CM_ERROR_NOSUCHFILE;
829 osi_assert(dscp != NULL && scp == NULL);
830 openAction = 2; /* created file */
831 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
832 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
833 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
835 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
836 smb_NotifyChange(FILE_ACTION_ADDED,
837 FILE_NOTIFY_CHANGE_FILE_NAME,
838 dscp, lastNamep, NULL, TRUE);
839 if (!excl && code == CM_ERROR_EXISTS) {
840 /* not an exclusive create, and someone else tried
841 * creating it already, then we open it anyway. We
842 * don't bother retrying after this, since if this next
843 * fails, that means that the file was deleted after we
846 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
850 setAttr.mask = CM_ATTRMASK_LENGTH;
851 setAttr.length.LowPart = 0;
852 setAttr.length.HighPart = 0;
853 code = cm_SetAttr(scp, &setAttr, userp,
856 } /* lookup succeeded */
860 /* we don't need this any longer */
861 if (dscp) cm_ReleaseSCache(dscp);
864 /* something went wrong creating or truncating the file */
865 if (scp) cm_ReleaseSCache(scp);
866 cm_ReleaseUser(userp);
867 smb_FreeTran2Packet(outp);
871 /* make sure we're about to open a file */
872 if (scp->fileType != CM_SCACHETYPE_FILE) {
873 cm_ReleaseSCache(scp);
874 cm_ReleaseUser(userp);
875 smb_FreeTran2Packet(outp);
876 return CM_ERROR_ISDIR;
879 /* now all we have to do is open the file itself */
880 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
883 /* save a pointer to the vnode */
886 /* compute open mode */
887 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
888 if (openMode == 1 || openMode == 2)
889 fidp->flags |= SMB_FID_OPENWRITE;
891 smb_ReleaseFID(fidp);
893 cm_Open(scp, 0, userp);
895 /* copy out remainder of the parms */
897 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
898 lock_ObtainMutex(&scp->mx);
900 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
901 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
902 outp->parmsp[parmSlot] = dosTime & 0xffff; parmSlot++;
903 outp->parmsp[parmSlot] = (dosTime>>16) & 0xffff; parmSlot++;
904 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
906 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
908 outp->parmsp[parmSlot] = openMode; parmSlot++;
909 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
910 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
912 /* and the final "always present" stuff */
913 outp->parmsp[parmSlot] = openAction; parmSlot++;
914 /* next write out the "unique" ID */
915 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
916 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
917 outp->parmsp[parmSlot] = 0; parmSlot++;
918 if (returnEALength) {
919 outp->parmsp[parmSlot] = 0; parmSlot++;
920 outp->parmsp[parmSlot] = 0; parmSlot++;
922 lock_ReleaseMutex(&scp->mx);
923 outp->totalData = 0; /* total # of data bytes */
924 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
926 smb_SendTran2Packet(vcp, outp, op);
928 smb_FreeTran2Packet(outp);
930 cm_ReleaseUser(userp);
931 /* leave scp held since we put it in fidp->scp */
935 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
937 return CM_ERROR_BADOP;
940 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
942 return CM_ERROR_BADOP;
945 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
947 smb_tran2Packet_t *outp;
948 smb_tran2QFSInfo_t qi;
951 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
953 osi_Log1(afsd_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
955 switch (p->parmsp[0]) {
956 case 1: responseSize = sizeof(qi.u.allocInfo); break;
957 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
958 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
959 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
960 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
961 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
962 default: return CM_ERROR_INVAL;
965 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
966 switch (p->parmsp[0]) {
969 qi.u.allocInfo.FSID = 0;
970 qi.u.allocInfo.sectorsPerAllocUnit = 1;
971 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
972 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
973 qi.u.allocInfo.bytesPerSector = 1024;
978 qi.u.volumeInfo.vsn = 1234;
979 qi.u.volumeInfo.vnCount = 4;
980 /* we're supposed to pad it out with zeroes to the end */
981 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
982 strcpy(qi.u.volumeInfo.label, "AFS");
987 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
988 qi.u.FSvolumeInfo.vsn = 1234;
989 qi.u.FSvolumeInfo.vnCount = 4;
990 strcpy(qi.u.FSvolumeInfo.label, "AFS");
996 temp.LowPart = 0x7fffffff;
997 qi.u.FSsizeInfo.totalAllocUnits = temp;
998 temp.LowPart = 0x3fffffff;
999 qi.u.FSsizeInfo.availAllocUnits = temp;
1000 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
1001 qi.u.FSsizeInfo.bytesPerSector = 1024;
1005 /* FS device info */
1006 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
1007 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
1011 /* FS attribute info */
1012 /* attributes, defined in WINNT.H:
1013 * FILE_CASE_SENSITIVE_SEARCH 0x1
1014 * FILE_CASE_PRESERVED_NAMES 0x2
1015 * <no name defined> 0x4000
1016 * If bit 0x4000 is not set, Windows 95 thinks
1017 * we can't handle long (non-8.3) names,
1018 * despite our protestations to the contrary.
1020 qi.u.FSattributeInfo.attributes = 0x4003;
1021 qi.u.FSattributeInfo.maxCompLength = 255;
1022 qi.u.FSattributeInfo.FSnameLength = 6;
1023 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
1027 /* copy out return data, and set corresponding sizes */
1028 outp->totalParms = 0;
1029 outp->totalData = responseSize;
1030 memcpy(outp->datap, &qi, responseSize);
1032 /* send and free the packets */
1033 smb_SendTran2Packet(vcp, outp, op);
1034 smb_FreeTran2Packet(outp);
1039 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1041 return CM_ERROR_BADOP;
1044 struct smb_ShortNameRock {
1048 size_t shortNameLen;
1051 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
1054 struct smb_ShortNameRock *rockp;
1058 /* compare both names and vnodes, though probably just comparing vnodes
1059 * would be safe enough.
1061 if (stricmp(dep->name, rockp->maskp) != 0)
1063 if (ntohl(dep->fid.vnode) != rockp->vnode)
1065 /* This is the entry */
1066 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1067 rockp->shortNameLen = shortNameEnd - rockp->shortName;
1068 return CM_ERROR_STOPNOW;
1071 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1072 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1074 struct smb_ShortNameRock rock;
1078 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1082 spacep = cm_GetSpace();
1083 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1085 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1087 cm_FreeSpace(spacep);
1088 if (code) return code;
1090 if (!lastNamep) lastNamep = pathp;
1093 thyper.HighPart = 0;
1094 rock.shortName = shortName;
1096 rock.maskp = lastNamep;
1097 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1100 cm_ReleaseSCache(dscp);
1103 return CM_ERROR_NOSUCHFILE;
1104 if (code == CM_ERROR_STOPNOW) {
1105 *shortNameLenp = rock.shortNameLen;
1111 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1113 smb_tran2Packet_t *outp;
1114 unsigned long dosTime;
1116 unsigned short infoLevel;
1118 unsigned short attributes;
1119 unsigned long extAttributes;
1124 cm_scache_t *scp, *dscp;
1133 infoLevel = p->parmsp[0];
1134 if (infoLevel == 6) nbytesRequired = 0;
1135 else if (infoLevel == 1) nbytesRequired = 22;
1136 else if (infoLevel == 2) nbytesRequired = 26;
1137 else if (infoLevel == 0x101) nbytesRequired = 40;
1138 else if (infoLevel == 0x102) nbytesRequired = 24;
1139 else if (infoLevel == 0x103) nbytesRequired = 4;
1140 else if (infoLevel == 0x108) nbytesRequired = 30;
1142 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1143 p->opcode, infoLevel);
1144 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1147 osi_Log2(afsd_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1148 osi_LogSaveString(afsd_logp, (char *)(&p->parmsp[3])));
1150 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1152 if (infoLevel > 0x100)
1153 outp->totalParms = 2;
1155 outp->totalParms = 0;
1156 outp->totalData = nbytesRequired;
1158 /* now, if we're at infoLevel 6, we're only being asked to check
1159 * the syntax, so we just OK things now. In particular, we're *not*
1160 * being asked to verify anything about the state of any parent dirs.
1162 if (infoLevel == 6) {
1163 smb_SendTran2Packet(vcp, outp, opx);
1164 smb_FreeTran2Packet(outp);
1168 userp = smb_GetTran2User(vcp, p);
1170 tidPathp = smb_GetTIDPath(vcp, p->tid);
1173 * XXX Strange hack XXX
1175 * As of Patch 7 (13 January 98), we are having the following problem:
1176 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1177 * requests to look up "desktop.ini" in all the subdirectories.
1178 * This can cause zillions of timeouts looking up non-existent cells
1179 * and volumes, especially in the top-level directory.
1181 * We have not found any way to avoid this or work around it except
1182 * to explicitly ignore the requests for mount points that haven't
1183 * yet been evaluated and for directories that haven't yet been
1186 if (infoLevel == 0x101) {
1187 spacep = cm_GetSpace();
1188 smb_StripLastComponent(spacep->data, &lastComp,
1189 (char *)(&p->parmsp[3]));
1190 if (strcmp(lastComp, "\\desktop.ini") == 0) {
1191 code = cm_NameI(cm_rootSCachep, spacep->data,
1195 userp, tidPathp, &req, &dscp);
1197 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1198 && !dscp->mountRootFidp)
1199 code = CM_ERROR_NOSUCHFILE;
1200 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1201 cm_buf_t *bp = buf_Find(dscp, &hzero);
1205 code = CM_ERROR_NOSUCHFILE;
1207 cm_ReleaseSCache(dscp);
1209 cm_FreeSpace(spacep);
1210 cm_ReleaseUser(userp);
1211 smb_SendTran2Error(vcp, p, opx, code);
1212 smb_FreeTran2Packet(outp);
1217 cm_FreeSpace(spacep);
1220 /* now do namei and stat, and copy out the info */
1221 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1222 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1225 cm_ReleaseUser(userp);
1226 smb_SendTran2Error(vcp, p, opx, code);
1227 smb_FreeTran2Packet(outp);
1231 lock_ObtainMutex(&scp->mx);
1232 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1233 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1234 if (code) goto done;
1236 /* now we have the status in the cache entry, and everything is locked.
1237 * Marshall the output data.
1240 /* for info level 108, figure out short name */
1241 if (infoLevel == 0x108) {
1242 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1243 tidPathp, scp->fid.vnode, shortName,
1250 *((u_long *)op) = len * 2; op += 4;
1251 mbstowcs((unsigned short *)op, shortName, len);
1256 if (infoLevel == 1 || infoLevel == 2) {
1257 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1258 *((u_long *)op) = dosTime; op += 4; /* creation time */
1259 *((u_long *)op) = dosTime; op += 4; /* access time */
1260 *((u_long *)op) = dosTime; op += 4; /* write time */
1261 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1262 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1263 attributes = smb_Attributes(scp);
1264 *((u_short *)op) = attributes; op += 2; /* attributes */
1266 else if (infoLevel == 0x101) {
1267 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1268 *((FILETIME *)op) = ft; op += 8; /* creation time */
1269 *((FILETIME *)op) = ft; op += 8; /* last access time */
1270 *((FILETIME *)op) = ft; op += 8; /* last write time */
1271 *((FILETIME *)op) = ft; op += 8; /* last change time */
1272 extAttributes = smb_ExtAttributes(scp);
1273 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1274 *((u_long *)op) = 0; op += 4; /* don't know what this is */
1276 else if (infoLevel == 0x102) {
1277 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1278 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1279 *((u_long *)op) = scp->linkCount; op += 4;
1282 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1285 else if (infoLevel == 0x103) {
1286 memset(op, 0, 4); op += 4; /* EA size */
1289 /* now, if we are being asked about extended attrs, return a 0 size */
1290 if (infoLevel == 2) {
1291 *((u_long *)op) = 0; op += 4;
1295 /* send and free the packets */
1297 lock_ReleaseMutex(&scp->mx);
1298 cm_ReleaseSCache(scp);
1299 cm_ReleaseUser(userp);
1300 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1301 else smb_SendTran2Error(vcp, p, opx, code);
1302 smb_FreeTran2Packet(outp);
1307 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1309 return CM_ERROR_BADOP;
1312 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1314 smb_tran2Packet_t *outp;
1316 unsigned long attributes;
1317 unsigned short infoLevel;
1330 fidp = smb_FindFID(vcp, fid, 0);
1333 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
1337 infoLevel = p->parmsp[1];
1338 if (infoLevel == 0x101) nbytesRequired = 40;
1339 else if (infoLevel == 0x102) nbytesRequired = 24;
1340 else if (infoLevel == 0x103) nbytesRequired = 4;
1341 else if (infoLevel == 0x104) nbytesRequired = 6;
1343 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1344 p->opcode, infoLevel);
1345 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1348 osi_Log2(afsd_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1350 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1352 if (infoLevel > 0x100)
1353 outp->totalParms = 2;
1355 outp->totalParms = 0;
1356 outp->totalData = nbytesRequired;
1358 userp = smb_GetTran2User(vcp, p);
1361 lock_ObtainMutex(&scp->mx);
1362 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1363 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1364 if (code) goto done;
1366 /* now we have the status in the cache entry, and everything is locked.
1367 * Marshall the output data.
1370 if (infoLevel == 0x101) {
1371 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1372 *((FILETIME *)op) = ft; op += 8; /* creation time */
1373 *((FILETIME *)op) = ft; op += 8; /* last access time */
1374 *((FILETIME *)op) = ft; op += 8; /* last write time */
1375 *((FILETIME *)op) = ft; op += 8; /* last change time */
1376 attributes = smb_ExtAttributes(scp);
1377 *((u_long *)op) = attributes; op += 4;
1378 *((u_long *)op) = 0; op += 4;
1380 else if (infoLevel == 0x102) {
1381 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1382 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1383 *((u_long *)op) = scp->linkCount; op += 4;
1384 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1386 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1389 else if (infoLevel == 0x103) {
1390 *((u_long *)op) = 0; op += 4;
1392 else if (infoLevel == 0x104) {
1396 if (fidp->NTopen_wholepathp)
1397 name = fidp->NTopen_wholepathp;
1399 name = "\\"; /* probably can't happen */
1401 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
1402 *((u_long *)op) = len * 2; op += 4;
1403 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1406 /* send and free the packets */
1408 lock_ReleaseMutex(&scp->mx);
1409 cm_ReleaseUser(userp);
1410 smb_ReleaseFID(fidp);
1411 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1412 else smb_SendTran2Error(vcp, p, opx, code);
1413 smb_FreeTran2Packet(outp);
1418 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1423 unsigned short infoLevel;
1424 smb_tran2Packet_t *outp;
1432 fidp = smb_FindFID(vcp, fid, 0);
1435 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1439 infoLevel = p->parmsp[1];
1440 if (infoLevel > 0x104 || infoLevel < 0x101) {
1441 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1442 p->opcode, infoLevel);
1443 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1447 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1448 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1451 if ((infoLevel == 0x103 || infoLevel == 0x104)
1452 && !(fidp->flags & SMB_FID_OPENWRITE)) {
1453 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1457 osi_Log1(afsd_logp, "T2 SFileInfo type 0x%x", infoLevel);
1459 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1461 outp->totalParms = 2;
1462 outp->totalData = 0;
1464 userp = smb_GetTran2User(vcp, p);
1468 if (infoLevel == 0x101) {
1470 unsigned int attribute;
1473 /* lock the vnode with a callback; we need the current status
1474 * to determine what the new status is, in some cases.
1476 lock_ObtainMutex(&scp->mx);
1477 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1478 CM_SCACHESYNC_GETSTATUS
1479 | CM_SCACHESYNC_NEEDCALLBACK);
1481 lock_ReleaseMutex(&scp->mx);
1485 /* prepare for setattr call */
1487 lastMod = *((FILETIME *)(p->datap + 16));
1488 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod))) {
1489 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1490 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1492 fidp->flags |= SMB_FID_MTIMESETDONE;
1494 attribute = *((u_long *)(p->datap + 32));
1495 if (attribute != 0) {
1496 if ((scp->unixModeBits & 0222)
1497 && (attribute & 1) != 0) {
1498 /* make a writable file read-only */
1499 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1500 attr.unixModeBits = scp->unixModeBits & ~0222;
1502 else if ((scp->unixModeBits & 0222) == 0
1503 && (attribute & 1) == 0) {
1504 /* make a read-only file writable */
1505 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1506 attr.unixModeBits = scp->unixModeBits | 0222;
1509 lock_ReleaseMutex(&scp->mx);
1513 code = cm_SetAttr(scp, &attr, userp, &req);
1517 else if (infoLevel == 0x103 || infoLevel == 0x104) {
1518 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1521 attr.mask = CM_ATTRMASK_LENGTH;
1522 attr.length.LowPart = size.LowPart;
1523 attr.length.HighPart = size.HighPart;
1524 code = cm_SetAttr(scp, &attr, userp, &req);
1526 else if (infoLevel == 0x102) {
1527 if (*((char *)(p->datap))) {
1528 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1531 fidp->flags |= SMB_FID_DELONCLOSE;
1535 fidp->flags &= ~SMB_FID_DELONCLOSE;
1539 cm_ReleaseUser(userp);
1540 smb_ReleaseFID(fidp);
1541 if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1542 else smb_SendTran2Error(vcp, p, op, code);
1543 smb_FreeTran2Packet(outp);
1548 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1550 return CM_ERROR_BADOP;
1553 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1555 return CM_ERROR_BADOP;
1558 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1560 return CM_ERROR_BADOP;
1563 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1565 return CM_ERROR_BADOP;
1568 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1570 return CM_ERROR_BADOP;
1573 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1574 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1579 cm_scache_t *targetScp; /* target if scp is a symlink */
1584 unsigned short attr;
1585 unsigned long lattr;
1586 smb_dirListPatch_t *patchp;
1587 smb_dirListPatch_t *npatchp;
1589 for(patchp = *dirPatchespp; patchp; patchp =
1590 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1591 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1593 lock_ObtainMutex(&scp->mx);
1594 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1595 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1597 lock_ReleaseMutex(&scp->mx);
1598 cm_ReleaseSCache(scp);
1602 /* now watch for a symlink */
1603 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1604 lock_ReleaseMutex(&scp->mx);
1605 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp,
1608 /* we have a more accurate file to use (the
1609 * target of the symbolic link). Otherwise,
1610 * we'll just use the symlink anyway.
1612 osi_Log2(afsd_logp, "symlink vp %x to vp %x",
1614 cm_ReleaseSCache(scp);
1617 lock_ObtainMutex(&scp->mx);
1620 dptr = patchp->dptr;
1622 if (infoLevel >= 0x101) {
1624 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1626 /* copy to Creation Time */
1627 *((FILETIME *)dptr) = ft;
1630 /* copy to Last Access Time */
1631 *((FILETIME *)dptr) = ft;
1634 /* copy to Last Write Time */
1635 *((FILETIME *)dptr) = ft;
1638 /* copy to Change Time */
1639 *((FILETIME *)dptr) = ft;
1642 /* Use length for both file length and alloc length */
1643 *((LARGE_INTEGER *)dptr) = scp->length;
1645 *((LARGE_INTEGER *)dptr) = scp->length;
1648 /* Copy attributes */
1649 lattr = smb_ExtAttributes(scp);
1650 *((u_long *)dptr) = lattr;
1655 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1657 /* and copy out date */
1658 shortTemp = (dosTime>>16) & 0xffff;
1659 *((u_short *)dptr) = shortTemp;
1662 /* copy out creation time */
1663 shortTemp = dosTime & 0xffff;
1664 *((u_short *)dptr) = shortTemp;
1667 /* and copy out date */
1668 shortTemp = (dosTime>>16) & 0xffff;
1669 *((u_short *)dptr) = shortTemp;
1672 /* copy out access time */
1673 shortTemp = dosTime & 0xffff;
1674 *((u_short *)dptr) = shortTemp;
1677 /* and copy out date */
1678 shortTemp = (dosTime>>16) & 0xffff;
1679 *((u_short *)dptr) = shortTemp;
1682 /* copy out mod time */
1683 shortTemp = dosTime & 0xffff;
1684 *((u_short *)dptr) = shortTemp;
1687 /* copy out file length and alloc length,
1688 * using the same for both
1690 *((u_long *)dptr) = scp->length.LowPart;
1692 *((u_long *)dptr) = scp->length.LowPart;
1695 /* finally copy out attributes as short */
1696 attr = smb_Attributes(scp);
1697 *dptr++ = attr & 0xff;
1698 *dptr++ = (attr >> 8) & 0xff;
1701 lock_ReleaseMutex(&scp->mx);
1702 cm_ReleaseSCache(scp);
1705 /* now free the patches */
1706 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1707 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1711 /* and mark the list as empty */
1712 *dirPatchespp = NULL;
1717 /* do a case-folding search of the star name mask with the name in namep.
1718 * Return 1 if we match, otherwise 0.
1720 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1722 unsigned char tcp1, tcp2; /* Pattern characters */
1723 unsigned char tcn1; /* Name characters */
1724 int sawDot = 0, sawStar = 0;
1725 char *starNamep, *starMaskp;
1726 static char nullCharp[] = {0};
1728 /* make sure we only match 8.3 names, if requested */
1729 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) return 0;
1733 /* Next pattern character */
1736 /* Next name character */
1740 /* 0 - end of pattern */
1746 else if (tcp1 == '.' || tcp1 == '"') {
1756 * first dot in pattern;
1757 * must match dot or end of name
1762 else if (tcn1 == '.') {
1771 else if (tcp1 == '?') {
1772 if (tcn1 == 0 || tcn1 == '.')
1777 else if (tcp1 == '>') {
1778 if (tcn1 != 0 && tcn1 != '.')
1782 else if (tcp1 == '*' || tcp1 == '<') {
1786 else if (tcp2 == '.' || tcp2 == '"') {
1787 while (tcn1 != '.' && tcn1 != 0)
1802 * pattern character after '*' is not null or
1803 * period. If it is '?' or '>', we are not
1804 * going to understand it. If it is '*' or
1805 * '<', we are going to skip over it. None of
1806 * these are likely, I hope.
1808 /* skip over '*' and '<' */
1809 while (tcp2 == '*' || tcp2 == '<')
1812 /* skip over characters that don't match tcp2 */
1813 while (tcn1 != '.' && tcn1 != 0
1814 && cm_foldUpper[tcn1] != cm_foldUpper[tcp2])
1818 if (tcn1 == '.' || tcn1 == 0)
1821 /* Remember where we are */
1831 /* tcp1 is not a wildcard */
1832 if (cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) {
1837 /* if trying to match a star pattern, go back */
1839 maskp = starMaskp - 2;
1840 namep = starNamep + 1;
1850 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1859 smb_dirListPatch_t *dirListPatchesp;
1860 smb_dirListPatch_t *curPatchp;
1863 long orbytes; /* # of bytes in this output record */
1864 long ohbytes; /* # of bytes, except file name */
1865 long onbytes; /* # of bytes in name, incl. term. null */
1866 osi_hyper_t dirLength;
1867 osi_hyper_t bufferOffset;
1868 osi_hyper_t curOffset;
1870 smb_dirSearch_t *dsp;
1874 cm_pageHeader_t *pageHeaderp;
1875 cm_user_t *userp = NULL;
1878 long nextEntryCookie;
1879 int numDirChunks; /* # of 32 byte dir chunks in this entry */
1880 char *op; /* output data ptr */
1881 char *origOp; /* original value of op */
1882 cm_space_t *spacep; /* for pathname buffer */
1883 long maxReturnData; /* max # of return data */
1884 long maxReturnParms; /* max # of return parms */
1885 long bytesInBuffer; /* # data bytes in the output buffer */
1887 char *maskp; /* mask part of path */
1891 smb_tran2Packet_t *outp; /* response packet */
1894 char shortName[13]; /* 8.3 name if needed */
1905 if (p->opcode == 1) {
1906 /* find first; obtain basic parameters from request */
1907 attribute = p->parmsp[0];
1908 maxCount = p->parmsp[1];
1909 infoLevel = p->parmsp[3];
1910 searchFlags = p->parmsp[2];
1911 dsp = smb_NewDirSearch(1);
1912 dsp->attribute = attribute;
1913 pathp = ((char *) p->parmsp) + 12; /* points to path */
1915 maskp = strrchr(pathp, '\\');
1916 if (maskp == NULL) maskp = pathp;
1917 else maskp++; /* skip over backslash */
1918 strcpy(dsp->mask, maskp); /* and save mask */
1919 /* track if this is likely to match a lot of entries */
1920 starPattern = smb_V3IsStarMask(maskp);
1923 osi_assert(p->opcode == 2);
1924 /* find next; obtain basic parameters from request or open dir file */
1925 dsp = smb_FindDirSearch(p->parmsp[0]);
1926 if (!dsp) return CM_ERROR_BADFD;
1927 attribute = dsp->attribute;
1928 maxCount = p->parmsp[1];
1929 infoLevel = p->parmsp[2];
1930 searchFlags = p->parmsp[5];
1932 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
1934 starPattern = 1; /* assume, since required a Find Next */
1938 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
1939 attribute, infoLevel, maxCount, searchFlags);
1941 osi_Log2(afsd_logp, "...T2 search op %d, nextCookie 0x%x",
1942 p->opcode, nextCookie);
1944 if (infoLevel >= 0x101)
1945 searchFlags &= ~4; /* no resume keys */
1947 dirListPatchesp = NULL;
1949 maxReturnData = p->maxReturnData;
1950 if (p->opcode == 1) /* find first */
1951 maxReturnParms = 10; /* bytes */
1953 maxReturnParms = 8; /* bytes */
1955 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
1956 if (maxReturnData > 6000) maxReturnData = 6000;
1957 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
1959 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
1962 osi_Log1(afsd_logp, "T2 receive search dir %s",
1963 osi_LogSaveString(afsd_logp, pathp));
1965 /* bail out if request looks bad */
1966 if (p->opcode == 1 && !pathp) {
1967 return CM_ERROR_BADSMB;
1970 osi_Log2(afsd_logp, "T2 dir search cookie 0x%x, connection %d",
1971 nextCookie, dsp->cookie);
1973 userp = smb_GetTran2User(vcp, p);
1975 /* try to get the vnode for the path name next */
1976 lock_ObtainMutex(&dsp->mx);
1983 spacep = cm_GetSpace();
1984 smb_StripLastComponent(spacep->data, NULL, pathp);
1985 lock_ReleaseMutex(&dsp->mx);
1987 tidPathp = smb_GetTIDPath(vcp, p->tid);
1988 code = cm_NameI(cm_rootSCachep, spacep->data,
1989 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
1990 userp, tidPathp, &req, &scp);
1991 cm_FreeSpace(spacep);
1993 lock_ObtainMutex(&dsp->mx);
1995 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
1997 /* we need one hold for the entry we just stored into,
1998 * and one for our own processing. When we're done
1999 * with this function, we'll drop the one for our own
2000 * processing. We held it once from the namei call,
2001 * and so we do another hold now.
2004 lock_ObtainMutex(&scp->mx);
2005 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2006 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2007 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2008 dsp->flags |= SMB_DIRSEARCH_BULKST;
2010 lock_ReleaseMutex(&scp->mx);
2013 lock_ReleaseMutex(&dsp->mx);
2015 cm_ReleaseUser(userp);
2016 smb_FreeTran2Packet(outp);
2017 smb_DeleteDirSearch(dsp);
2018 smb_ReleaseDirSearch(dsp);
2022 /* get the directory size */
2023 lock_ObtainMutex(&scp->mx);
2024 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2025 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2027 lock_ReleaseMutex(&scp->mx);
2028 cm_ReleaseSCache(scp);
2029 cm_ReleaseUser(userp);
2030 smb_FreeTran2Packet(outp);
2031 smb_DeleteDirSearch(dsp);
2032 smb_ReleaseDirSearch(dsp);
2036 dirLength = scp->length;
2038 bufferOffset.LowPart = bufferOffset.HighPart = 0;
2039 curOffset.HighPart = 0;
2040 curOffset.LowPart = nextCookie;
2041 origOp = outp->datap;
2048 if (searchFlags & 4)
2049 /* skip over resume key */
2052 /* make sure that curOffset.LowPart doesn't point to the first
2053 * 32 bytes in the 2nd through last dir page, and that it doesn't
2054 * point at the first 13 32-byte chunks in the first dir page,
2055 * since those are dir and page headers, and don't contain useful
2058 temp = curOffset.LowPart & (2048-1);
2059 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2060 /* we're in the first page */
2061 if (temp < 13*32) temp = 13*32;
2064 /* we're in a later dir page */
2065 if (temp < 32) temp = 32;
2068 /* make sure the low order 5 bits are zero */
2071 /* now put temp bits back ito curOffset.LowPart */
2072 curOffset.LowPart &= ~(2048-1);
2073 curOffset.LowPart |= temp;
2075 /* check if we've returned all the names that will fit in the
2076 * response packet; we check return count as well as the number
2077 * of bytes requested. We check the # of bytes after we find
2078 * the dir entry, since we'll need to check its size.
2080 if (returnedNames >= maxCount) break;
2082 /* check if we've passed the dir's EOF */
2083 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2088 /* see if we can use the bufferp we have now; compute in which
2089 * page the current offset would be, and check whether that's
2090 * the offset of the buffer we have. If not, get the buffer.
2092 thyper.HighPart = curOffset.HighPart;
2093 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2094 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2097 buf_Release(bufferp);
2100 lock_ReleaseMutex(&scp->mx);
2101 lock_ObtainRead(&scp->bufCreateLock);
2102 code = buf_Get(scp, &thyper, &bufferp);
2103 lock_ReleaseRead(&scp->bufCreateLock);
2105 /* now, if we're doing a star match, do bulk fetching
2106 * of all of the status info for files in the dir.
2109 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2112 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2113 && LargeIntegerGreaterThanOrEqualTo(
2114 thyper, scp->bulkStatProgress)) {
2115 /* Don't bulk stat if risking timeout */
2116 int now = GetCurrentTime();
2117 if (now - req.startTime > 5000) {
2118 scp->bulkStatProgress = thyper;
2119 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2120 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2122 cm_TryBulkStat(scp, &thyper,
2127 lock_ObtainMutex(&scp->mx);
2129 bufferOffset = thyper;
2131 /* now get the data in the cache */
2133 code = cm_SyncOp(scp, bufferp, userp, &req,
2135 CM_SCACHESYNC_NEEDCALLBACK
2136 | CM_SCACHESYNC_READ);
2139 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2141 /* otherwise, load the buffer and try again */
2142 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2147 buf_Release(bufferp);
2151 } /* if (wrong buffer) ... */
2153 /* now we have the buffer containing the entry we're interested
2154 * in; copy it out if it represents a non-deleted entry.
2156 entryInDir = curOffset.LowPart & (2048-1);
2157 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2159 /* page header will help tell us which entries are free. Page
2160 * header can change more often than once per buffer, since
2161 * AFS 3 dir page size may be less than (but not more than)
2162 * a buffer package buffer.
2164 /* only look intra-buffer */
2165 temp = curOffset.LowPart & (buf_bufferSize - 1);
2166 temp &= ~(2048 - 1); /* turn off intra-page bits */
2167 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2169 /* now determine which entry we're looking at in the page.
2170 * If it is free (there's a free bitmap at the start of the
2171 * dir), we should skip these 32 bytes.
2173 slotInPage = (entryInDir & 0x7e0) >> 5;
2174 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2175 & (1 << (slotInPage & 0x7)))) {
2176 /* this entry is free */
2177 numDirChunks = 1; /* only skip this guy */
2181 tp = bufferp->datap + entryInBuffer;
2182 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
2184 /* while we're here, compute the next entry's location, too,
2185 * since we'll need it when writing out the cookie into the dir
2188 * XXXX Probably should do more sanity checking.
2190 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2192 /* compute offset of cookie representing next entry */
2193 nextEntryCookie = curOffset.LowPart
2194 + (CM_DIR_CHUNKSIZE * numDirChunks);
2196 /* Need 8.3 name? */
2198 if (infoLevel == 0x104
2199 && dep->fid.vnode != 0
2200 && !cm_Is8Dot3(dep->name)) {
2201 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2205 if (dep->fid.vnode != 0
2206 && (smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)
2208 && smb_V3MatchMask(shortName, maskp,
2209 CM_FLAG_CASEFOLD)))) {
2211 /* Eliminate entries that don't match requested
2213 if (!(dsp->attribute & 0x10)) /* no directories */
2215 /* We have already done the cm_TryBulkStat above */
2216 fid.cell = scp->fid.cell;
2217 fid.volume = scp->fid.volume;
2218 fid.vnode = ntohl(dep->fid.vnode);
2219 fid.unique = ntohl(dep->fid.unique);
2220 fileType = cm_FindFileType(&fid);
2221 /*osi_Log2(afsd_logp, "smb_ReceiveTran2SearchDir: file %s "
2222 "has filetype %d", dep->name,
2224 if (fileType == CM_SCACHETYPE_DIRECTORY)
2228 /* finally check if this name will fit */
2230 /* standard dir entry stuff */
2231 if (infoLevel < 0x101)
2232 ohbytes = 23; /* pre-NT */
2233 else if (infoLevel == 0x103)
2234 ohbytes = 12; /* NT names only */
2236 ohbytes = 64; /* NT */
2238 if (infoLevel == 0x104)
2239 ohbytes += 26; /* Short name & length */
2241 if (searchFlags & 4) {
2242 ohbytes += 4; /* if resume key required */
2246 && infoLevel != 0x101
2247 && infoLevel != 0x103)
2248 ohbytes += 4; /* EASIZE */
2250 /* add header to name & term. null */
2251 orbytes = onbytes + ohbytes + 1;
2253 /* now, we round up the record to a 4 byte alignment,
2254 * and we make sure that we have enough room here for
2255 * even the aligned version (so we don't have to worry
2256 * about an * overflow when we pad things out below).
2257 * That's the reason for the alignment arithmetic below.
2259 if (infoLevel >= 0x101)
2260 align = (4 - (orbytes & 3)) & 3;
2263 if (orbytes + bytesInBuffer + align > maxReturnData)
2266 /* this is one of the entries to use: it is not deleted
2267 * and it matches the star pattern we're looking for.
2268 * Put out the name, preceded by its length.
2270 /* First zero everything else */
2271 memset(origOp, 0, ohbytes);
2273 if (infoLevel <= 0x101)
2274 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2275 else if (infoLevel == 0x103)
2276 *((u_long *)(op + 8)) = onbytes;
2278 *((u_long *)(op + 60)) = onbytes;
2279 strcpy(origOp+ohbytes, dep->name);
2281 /* Short name if requested and needed */
2282 if (infoLevel == 0x104) {
2283 if (NeedShortName) {
2284 strcpy(op + 70, shortName);
2285 *(op + 68) = shortNameEnd - shortName;
2289 /* now, adjust the # of entries copied */
2292 /* NextEntryOffset and FileIndex */
2293 if (infoLevel >= 101) {
2294 int entryOffset = orbytes + align;
2295 *((u_long *)op) = entryOffset;
2296 *((u_long *)(op+4)) = nextEntryCookie;
2299 /* now we emit the attribute. This is tricky, since
2300 * we need to really stat the file to find out what
2301 * type of entry we've got. Right now, we're copying
2302 * out data from * a buffer, while holding the scp
2303 * locked, so it isn't really convenient to stat
2304 * something now. We'll put in a place holder
2305 * now, and make a second pass before returning this
2306 * to get the real attributes. So, we just skip the
2307 * data for now, and adjust it later. We allocate a
2308 * patch record to make it easy to find this point
2309 * later. The replay will happen at a time when it is
2310 * safe to unlock the directory.
2312 if (infoLevel != 0x103) {
2313 curPatchp = malloc(sizeof(*curPatchp));
2314 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2316 curPatchp->dptr = op;
2317 if (infoLevel >= 0x101)
2318 curPatchp->dptr += 8;
2319 curPatchp->fid.cell = scp->fid.cell;
2320 curPatchp->fid.volume = scp->fid.volume;
2321 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2322 curPatchp->fid.unique = ntohl(dep->fid.unique);
2325 if (searchFlags & 4)
2326 /* put out resume key */
2327 *((u_long *)origOp) = nextEntryCookie;
2329 /* Adjust byte ptr and count */
2330 origOp += orbytes; /* skip entire record */
2331 bytesInBuffer += orbytes;
2333 /* and pad the record out */
2334 while (--align >= 0) {
2339 } /* if we're including this name */
2342 /* and adjust curOffset to be where the new cookie is */
2343 thyper.HighPart = 0;
2344 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2345 curOffset = LargeIntegerAdd(thyper, curOffset);
2346 } /* while copying data for dir listing */
2348 /* release the mutex */
2349 lock_ReleaseMutex(&scp->mx);
2350 if (bufferp) buf_Release(bufferp);
2352 /* apply and free last set of patches; if not doing a star match, this
2353 * will be empty, but better safe (and freeing everything) than sorry.
2355 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2358 /* now put out the final parameters */
2359 if (returnedNames == 0) eos = 1;
2360 if (p->opcode == 1) {
2362 outp->parmsp[0] = (unsigned short) dsp->cookie;
2363 outp->parmsp[1] = returnedNames;
2364 outp->parmsp[2] = eos;
2365 outp->parmsp[3] = 0; /* nothing wrong with EAS */
2366 outp->parmsp[4] = 0; /* don't need last name to continue
2367 * search, cookie is enough. Normally,
2368 * this is the offset of the file name
2369 * of the last entry returned.
2371 outp->totalParms = 10; /* in bytes */
2375 outp->parmsp[0] = returnedNames;
2376 outp->parmsp[1] = eos;
2377 outp->parmsp[2] = 0; /* EAS error */
2378 outp->parmsp[3] = 0; /* last name, as above */
2379 outp->totalParms = 8; /* in bytes */
2382 /* return # of bytes in the buffer */
2383 outp->totalData = bytesInBuffer;
2385 osi_Log2(afsd_logp, "T2 search dir done, %d names, code %d",
2386 returnedNames, code);
2388 /* Return error code if unsuccessful on first request */
2389 if (code == 0 && p->opcode == 1 && returnedNames == 0)
2390 code = CM_ERROR_NOSUCHFILE;
2392 /* if we're supposed to close the search after this request, or if
2393 * we're supposed to close the search if we're done, and we're done,
2394 * or if something went wrong, close the search.
2396 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2397 if ((searchFlags & 1) || (returnedNames == 0)
2398 || code != 0) smb_DeleteDirSearch(dsp);
2400 smb_SendTran2Error(vcp, p, opx, code);
2402 smb_SendTran2Packet(vcp, outp, opx);
2404 smb_FreeTran2Packet(outp);
2405 smb_ReleaseDirSearch(dsp);
2406 cm_ReleaseSCache(scp);
2407 cm_ReleaseUser(userp);
2411 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2414 smb_dirSearch_t *dsp;
2416 dirHandle = smb_GetSMBParm(inp, 0);
2418 osi_Log1(afsd_logp, "SMB3 find close handle %d", dirHandle);
2420 dsp = smb_FindDirSearch(dirHandle);
2423 return CM_ERROR_BADFD;
2425 /* otherwise, we have an FD to destroy */
2426 smb_DeleteDirSearch(dsp);
2427 smb_ReleaseDirSearch(dsp);
2429 /* and return results */
2430 smb_SetSMBDataLength(outp, 0);
2435 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2437 smb_SetSMBDataLength(outp, 0);
2441 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2448 cm_scache_t *dscp; /* dir we're dealing with */
2449 cm_scache_t *scp; /* file we're creating */
2451 int initialModeBits;
2461 int parmSlot; /* which parm we're dealing with */
2469 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
2470 openFun = smb_GetSMBParm(inp, 8); /* open function */
2471 excl = ((openFun & 3) == 0);
2472 trunc = ((openFun & 3) == 2); /* truncate it */
2473 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2474 openAction = 0; /* tracks what we did */
2476 attributes = smb_GetSMBParm(inp, 5);
2477 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2479 /* compute initial mode bits based on read-only flag in attributes */
2480 initialModeBits = 0666;
2481 if (attributes & 1) initialModeBits &= ~0222;
2483 pathp = smb_GetSMBData(inp, NULL);
2485 spacep = inp->spacep;
2486 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2488 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2489 /* special case magic file name for receiving IOCTL requests
2490 * (since IOCTL calls themselves aren't getting through).
2492 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2493 smb_SetupIoctlFid(fidp, spacep);
2495 /* set inp->fid so that later read calls in same msg can find fid */
2496 inp->fid = fidp->fid;
2498 /* copy out remainder of the parms */
2500 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2502 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2503 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
2504 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2505 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
2506 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2507 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2508 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2509 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2511 /* and the final "always present" stuff */
2512 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2513 /* next write out the "unique" ID */
2514 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2515 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2516 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2517 smb_SetSMBDataLength(outp, 0);
2519 /* and clean up fid reference */
2520 smb_ReleaseFID(fidp);
2524 userp = smb_GetUser(vcp, inp);
2527 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2528 code = cm_NameI(cm_rootSCachep, pathp,
2529 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2530 userp, tidPathp, &req, &scp);
2532 code = cm_NameI(cm_rootSCachep, spacep->data,
2533 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2534 userp, tidPathp, &req, &dscp);
2537 cm_ReleaseUser(userp);
2541 /* otherwise, scp points to the parent directory. Do a lookup,
2542 * and truncate the file if we find it, otherwise we create the
2545 if (!lastNamep) lastNamep = pathp;
2547 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2549 if (code && code != CM_ERROR_NOSUCHFILE) {
2550 cm_ReleaseSCache(dscp);
2551 cm_ReleaseUser(userp);
2556 /* if we get here, if code is 0, the file exists and is represented by
2557 * scp. Otherwise, we have to create it. The dir may be represented
2558 * by dscp, or we may have found the file directly. If code is non-zero,
2562 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2564 if (dscp) cm_ReleaseSCache(dscp);
2565 cm_ReleaseSCache(scp);
2566 cm_ReleaseUser(userp);
2571 /* oops, file shouldn't be there */
2572 if (dscp) cm_ReleaseSCache(dscp);
2573 cm_ReleaseSCache(scp);
2574 cm_ReleaseUser(userp);
2575 return CM_ERROR_EXISTS;
2579 setAttr.mask = CM_ATTRMASK_LENGTH;
2580 setAttr.length.LowPart = 0;
2581 setAttr.length.HighPart = 0;
2582 code = cm_SetAttr(scp, &setAttr, userp, &req);
2583 openAction = 3; /* truncated existing file */
2585 else openAction = 1; /* found existing file */
2587 else if (!(openFun & 0x10)) {
2588 /* don't create if not found */
2589 if (dscp) cm_ReleaseSCache(dscp);
2590 cm_ReleaseUser(userp);
2591 return CM_ERROR_NOSUCHFILE;
2594 osi_assert(dscp != NULL);
2595 osi_Log1(afsd_logp, "smb_ReceiveV3OpenX creating file %s",
2596 osi_LogSaveString(afsd_logp, lastNamep));
2597 openAction = 2; /* created file */
2598 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2599 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2600 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2602 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2603 smb_NotifyChange(FILE_ACTION_ADDED,
2604 FILE_NOTIFY_CHANGE_FILE_NAME,
2605 dscp, lastNamep, NULL, TRUE);
2606 if (!excl && code == CM_ERROR_EXISTS) {
2607 /* not an exclusive create, and someone else tried
2608 * creating it already, then we open it anyway. We
2609 * don't bother retrying after this, since if this next
2610 * fails, that means that the file was deleted after we
2611 * started this call.
2613 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2617 setAttr.mask = CM_ATTRMASK_LENGTH;
2618 setAttr.length.LowPart = 0;
2619 setAttr.length.HighPart = 0;
2620 code = cm_SetAttr(scp, &setAttr, userp,
2623 } /* lookup succeeded */
2627 /* we don't need this any longer */
2628 if (dscp) cm_ReleaseSCache(dscp);
2631 /* something went wrong creating or truncating the file */
2632 if (scp) cm_ReleaseSCache(scp);
2633 cm_ReleaseUser(userp);
2637 /* make sure we're about to open a file */
2638 if (scp->fileType != CM_SCACHETYPE_FILE) {
2639 cm_ReleaseSCache(scp);
2640 cm_ReleaseUser(userp);
2641 return CM_ERROR_ISDIR;
2644 /* now all we have to do is open the file itself */
2645 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2648 /* save a pointer to the vnode */
2651 /* compute open mode */
2652 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2653 if (openMode == 1 || openMode == 2)
2654 fidp->flags |= SMB_FID_OPENWRITE;
2656 smb_ReleaseFID(fidp);
2658 cm_Open(scp, 0, userp);
2660 /* set inp->fid so that later read calls in same msg can find fid */
2661 inp->fid = fidp->fid;
2663 /* copy out remainder of the parms */
2665 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2666 lock_ObtainMutex(&scp->mx);
2668 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2669 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2670 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2671 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2672 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2673 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2674 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2675 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2676 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2678 /* and the final "always present" stuff */
2679 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2680 /* next write out the "unique" ID */
2681 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2682 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2683 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2684 lock_ReleaseMutex(&scp->mx);
2685 smb_SetSMBDataLength(outp, 0);
2687 osi_Log1(afsd_logp, "SMB OpenX opening fid %d", fidp->fid);
2689 cm_ReleaseUser(userp);
2690 /* leave scp held since we put it in fidp->scp */
2694 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2701 unsigned char LockType;
2702 unsigned short NumberOfUnlocks, NumberOfLocks;
2703 unsigned long Timeout;
2705 LARGE_INTEGER LOffset, LLength;
2706 smb_waitingLock_t *waitingLock;
2713 fid = smb_GetSMBParm(inp, 2);
2714 fid = smb_ChainFID(fid, inp);
2716 fidp = smb_FindFID(vcp, fid, 0);
2717 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2718 return CM_ERROR_BADFD;
2720 /* set inp->fid so that later read calls in same msg can find fid */
2723 userp = smb_GetUser(vcp, inp);
2727 lock_ObtainMutex(&scp->mx);
2728 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2729 CM_SCACHESYNC_NEEDCALLBACK
2730 | CM_SCACHESYNC_GETSTATUS
2731 | CM_SCACHESYNC_LOCK);
2732 if (code) goto doneSync;
2734 LockType = smb_GetSMBParm(inp, 3) & 0xff;
2735 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2736 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2737 NumberOfLocks = smb_GetSMBParm(inp, 7);
2739 op = smb_GetSMBData(inp, NULL);
2741 for (i=0; i<NumberOfUnlocks; i++) {
2742 if (LockType & 0x10) {
2744 LOffset.HighPart = *((LONG *)(op + 4));
2745 LOffset.LowPart = *((DWORD *)(op + 8));
2746 LLength.HighPart = *((LONG *)(op + 12));
2747 LLength.LowPart = *((DWORD *)(op + 16));
2751 /* Not Large Files */
2752 LOffset.HighPart = 0;
2753 LOffset.LowPart = *((DWORD *)(op + 2));
2754 LLength.HighPart = 0;
2755 LLength.LowPart = *((DWORD *)(op + 6));
2758 if (LargeIntegerNotEqualToZero(LOffset))
2760 /* Do not check length -- length check done in cm_Unlock */
2762 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2763 if (code) goto done;
2766 for (i=0; i<NumberOfLocks; i++) {
2767 if (LockType & 0x10) {
2769 LOffset.HighPart = *((LONG *)(op + 4));
2770 LOffset.LowPart = *((DWORD *)(op + 8));
2771 LLength.HighPart = *((LONG *)(op + 12));
2772 LLength.LowPart = *((DWORD *)(op + 16));
2776 /* Not Large Files */
2777 LOffset.HighPart = 0;
2778 LOffset.LowPart = *((DWORD *)(op + 2));
2779 LLength.HighPart = 0;
2780 LLength.LowPart = *((DWORD *)(op + 6));
2783 if (LargeIntegerNotEqualToZero(LOffset))
2785 if (LargeIntegerLessThan(LOffset, scp->length))
2788 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2789 userp, &req, &lockp);
2790 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2791 /* Put on waiting list */
2792 waitingLock = malloc(sizeof(smb_waitingLock_t));
2793 waitingLock->vcp = vcp;
2794 waitingLock->inp = smb_CopyPacket(inp);
2795 waitingLock->outp = smb_CopyPacket(outp);
2796 waitingLock->timeRemaining = Timeout;
2797 waitingLock->lockp = lockp;
2798 lock_ObtainWrite(&smb_globalLock);
2799 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2801 osi_Wakeup((long) &smb_allWaitingLocks);
2802 lock_ReleaseWrite(&smb_globalLock);
2803 /* don't send reply immediately */
2804 outp->flags |= SMB_PACKETFLAG_NOSEND;
2810 /* release any locks acquired before the failure */
2813 smb_SetSMBDataLength(outp, 0);
2815 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2817 lock_ReleaseMutex(&scp->mx);
2818 cm_ReleaseUser(userp);
2819 smb_ReleaseFID(fidp);
2824 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2836 fid = smb_GetSMBParm(inp, 0);
2837 fid = smb_ChainFID(fid, inp);
2839 fidp = smb_FindFID(vcp, fid, 0);
2840 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2841 return CM_ERROR_BADFD;
2844 userp = smb_GetUser(vcp, inp);
2848 /* otherwise, stat the file */
2849 lock_ObtainMutex(&scp->mx);
2850 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2851 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2852 if (code) goto done;
2854 /* decode times. We need a search time, but the response to this
2855 * call provides the date first, not the time, as returned in the
2856 * searchTime variable. So we take the high-order bits first.
2858 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2859 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
2860 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2861 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
2862 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2863 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
2864 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2866 /* now handle file size and allocation size */
2867 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
2868 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2869 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
2870 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2872 /* file attribute */
2873 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2875 /* and finalize stuff */
2876 smb_SetSMBDataLength(outp, 0);
2880 lock_ReleaseMutex(&scp->mx);
2881 cm_ReleaseUser(userp);
2882 smb_ReleaseFID(fidp);
2886 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2900 fid = smb_GetSMBParm(inp, 0);
2901 fid = smb_ChainFID(fid, inp);
2903 fidp = smb_FindFID(vcp, fid, 0);
2904 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2905 return CM_ERROR_BADFD;
2908 userp = smb_GetUser(vcp, inp);
2912 /* now prepare to call cm_setattr. This message only sets various times,
2913 * and AFS only implements mtime, and we'll set the mtime if that's
2914 * requested. The others we'll ignore.
2916 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
2918 if (searchTime != 0) {
2919 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
2920 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
2921 attrs.clientModTime = unixTime;
2922 code = cm_SetAttr(scp, &attrs, userp, &req);
2926 cm_ReleaseUser(userp);
2927 smb_ReleaseFID(fidp);
2932 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2935 long count, finalCount;
2942 fd = smb_GetSMBParm(inp, 2);
2943 count = smb_GetSMBParm(inp, 5);
2944 offset.HighPart = 0; /* too bad */
2945 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
2947 osi_Log3(afsd_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
2948 fd, offset.LowPart, count);
2950 fd = smb_ChainFID(fd, inp);
2951 fidp = smb_FindFID(vcp, fd, 0);
2953 return CM_ERROR_BADFD;
2955 /* set inp->fid so that later read calls in same msg can find fid */
2958 if (fidp->flags & SMB_FID_IOCTL) {
2959 return smb_IoctlV3Read(fidp, vcp, inp, outp);
2962 userp = smb_GetUser(vcp, inp);
2964 /* 0 and 1 are reserved for request chaining, were setup by our caller,
2965 * and will be further filled in after we return.
2967 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
2968 smb_SetSMBParm(outp, 3, 0); /* resvd */
2969 smb_SetSMBParm(outp, 4, 0); /* resvd */
2970 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
2971 /* fill in #6 when we have all the parameters' space reserved */
2972 smb_SetSMBParm(outp, 7, 0); /* resv'd */
2973 smb_SetSMBParm(outp, 8, 0); /* resv'd */
2974 smb_SetSMBParm(outp, 9, 0); /* resv'd */
2975 smb_SetSMBParm(outp, 10, 0); /* resv'd */
2976 smb_SetSMBParm(outp, 11, 0); /* reserved */
2978 /* get op ptr after putting in the parms, since otherwise we don't
2979 * know where the data really is.
2981 op = smb_GetSMBData(outp, NULL);
2983 /* now fill in offset from start of SMB header to first data byte (to op) */
2984 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
2986 /* set the packet data length the count of the # of bytes */
2987 smb_SetSMBDataLength(outp, count);
2990 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
2992 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
2995 /* fix some things up */
2996 smb_SetSMBParm(outp, 5, finalCount);
2997 smb_SetSMBDataLength(outp, finalCount);
2999 smb_ReleaseFID(fidp);
3001 cm_ReleaseUser(userp);
3006 * Values for createDisp, copied from NTDDK.H
3008 * FILE_SUPERSEDE 0 (???)
3009 * FILE_OPEN 1 (open)
3010 * FILE_CREATE 2 (exclusive)
3011 * FILE_OPEN_IF 3 (non-exclusive)
3012 * FILE_OVERWRITE 4 (open & truncate, but do not create)
3013 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
3016 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3018 char *pathp, *realPathp;
3022 cm_scache_t *dscp; /* parent dir */
3023 cm_scache_t *scp; /* file to create or open */
3026 unsigned short nameLength;
3028 unsigned int requestOpLock;
3029 unsigned int requestBatchOpLock;
3030 unsigned int mustBeDir;
3032 unsigned int desiredAccess;
3033 unsigned int extAttributes;
3034 unsigned int createDisp;
3035 unsigned int createOptions;
3036 int initialModeBits;
3037 unsigned short baseFid;
3038 smb_fid_t *baseFidp;
3040 cm_scache_t *baseDirp;
3041 unsigned short openAction;
3055 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3056 flags = smb_GetSMBOffsetParm(inp, 3, 1)
3057 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3058 requestOpLock = flags & 0x02;
3059 requestBatchOpLock = flags & 0x04;
3060 mustBeDir = flags & 0x08;
3063 * Why all of a sudden 32-bit FID?
3064 * We will reject all bits higher than 16.
3066 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3067 return CM_ERROR_INVAL;
3068 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3069 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3070 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3071 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3072 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3073 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3074 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3075 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3076 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3078 /* mustBeDir is never set; createOptions directory bit seems to be
3081 if (createOptions & 1)
3083 else if (createOptions & 0x40)
3089 * compute initial mode bits based on read-only flag in
3090 * extended attributes
3092 initialModeBits = 0666;
3093 if (extAttributes & 1) initialModeBits &= ~0222;
3095 pathp = smb_GetSMBData(inp, NULL);
3096 /* Sometimes path is not null-terminated, so we make a copy. */
3097 realPathp = malloc(nameLength+1);
3098 memcpy(realPathp, pathp, nameLength);
3099 realPathp[nameLength] = 0;
3101 spacep = inp->spacep;
3102 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3104 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3105 /* special case magic file name for receiving IOCTL requests
3106 * (since IOCTL calls themselves aren't getting through).
3108 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3109 smb_SetupIoctlFid(fidp, spacep);
3111 /* set inp->fid so that later read calls in same msg can find fid */
3112 inp->fid = fidp->fid;
3116 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3117 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3118 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3120 memset(&ft, 0, sizeof(ft));
3121 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3122 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3123 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3124 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3125 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3126 sz.HighPart = 0x7fff; sz.LowPart = 0;
3127 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3128 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3129 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3130 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3131 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
3132 smb_SetSMBDataLength(outp, 0);
3134 /* clean up fid reference */
3135 smb_ReleaseFID(fidp);
3140 userp = smb_GetUser(vcp, inp);
3143 baseDirp = cm_rootSCachep;
3144 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3147 baseFidp = smb_FindFID(vcp, baseFid, 0);
3148 baseDirp = baseFidp->scp;
3152 /* compute open mode */
3154 if (desiredAccess & DELETE)
3155 fidflags |= SMB_FID_OPENDELETE;
3156 if (desiredAccess & AFS_ACCESS_READ)
3157 fidflags |= SMB_FID_OPENREAD;
3158 if (desiredAccess & AFS_ACCESS_WRITE)
3159 fidflags |= SMB_FID_OPENWRITE;
3163 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3164 userp, tidPathp, &req, &scp);
3165 if (code == 0) foundscp = TRUE;
3167 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3168 /* look up parent directory */
3169 code = cm_NameI(baseDirp, spacep->data,
3170 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3171 userp, tidPathp, &req, &dscp);
3173 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3176 cm_ReleaseUser(userp);
3181 if (!lastNamep) lastNamep = realPathp;
3184 if (!smb_IsLegalFilename(lastNamep))
3185 return CM_ERROR_BADNTFILENAME;
3188 code = cm_Lookup(dscp, lastNamep,
3189 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3191 if (code && code != CM_ERROR_NOSUCHFILE) {
3192 cm_ReleaseSCache(dscp);
3193 cm_ReleaseUser(userp);
3200 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3203 /* if we get here, if code is 0, the file exists and is represented by
3204 * scp. Otherwise, we have to create it. The dir may be represented
3205 * by dscp, or we may have found the file directly. If code is non-zero,
3209 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3212 if (dscp) cm_ReleaseSCache(dscp);
3213 cm_ReleaseSCache(scp);
3214 cm_ReleaseUser(userp);
3219 if (createDisp == 2) {
3220 /* oops, file shouldn't be there */
3221 if (dscp) cm_ReleaseSCache(dscp);
3222 cm_ReleaseSCache(scp);
3223 cm_ReleaseUser(userp);
3225 return CM_ERROR_EXISTS;
3229 || createDisp == 5) {
3230 setAttr.mask = CM_ATTRMASK_LENGTH;
3231 setAttr.length.LowPart = 0;
3232 setAttr.length.HighPart = 0;
3233 code = cm_SetAttr(scp, &setAttr, userp, &req);
3234 openAction = 3; /* truncated existing file */
3236 else openAction = 1; /* found existing file */
3238 else if (createDisp == 1 || createDisp == 4) {
3239 /* don't create if not found */
3240 if (dscp) cm_ReleaseSCache(dscp);
3241 cm_ReleaseUser(userp);
3243 return CM_ERROR_NOSUCHFILE;
3245 else if (realDirFlag == 0 || realDirFlag == -1) {
3246 osi_assert(dscp != NULL);
3247 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating file %s",
3248 osi_LogSaveString(afsd_logp, lastNamep));
3249 openAction = 2; /* created file */
3250 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3251 setAttr.clientModTime = time(NULL);
3252 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3254 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3255 smb_NotifyChange(FILE_ACTION_ADDED,
3256 FILE_NOTIFY_CHANGE_FILE_NAME,
3257 dscp, lastNamep, NULL, TRUE);
3258 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3259 /* Not an exclusive create, and someone else tried
3260 * creating it already, then we open it anyway. We
3261 * don't bother retrying after this, since if this next
3262 * fails, that means that the file was deleted after we
3263 * started this call.
3265 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3268 if (createDisp == 5) {
3269 setAttr.mask = CM_ATTRMASK_LENGTH;
3270 setAttr.length.LowPart = 0;
3271 setAttr.length.HighPart = 0;
3272 code = cm_SetAttr(scp, &setAttr, userp,
3275 } /* lookup succeeded */
3279 /* create directory */
3280 osi_assert(dscp != NULL);
3281 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating directory %s",
3282 osi_LogSaveString(afsd_logp, lastNamep));
3283 openAction = 2; /* created directory */
3284 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3285 setAttr.clientModTime = time(NULL);
3286 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3287 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3288 smb_NotifyChange(FILE_ACTION_ADDED,
3289 FILE_NOTIFY_CHANGE_DIR_NAME,
3290 dscp, lastNamep, NULL, TRUE);
3292 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3293 /* Not an exclusive create, and someone else tried
3294 * creating it already, then we open it anyway. We
3295 * don't bother retrying after this, since if this next
3296 * fails, that means that the file was deleted after we
3297 * started this call.
3299 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3305 /* something went wrong creating or truncating the file */
3306 if (scp) cm_ReleaseSCache(scp);
3307 cm_ReleaseUser(userp);
3312 /* make sure we have file vs. dir right */
3313 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3314 cm_ReleaseSCache(scp);
3315 cm_ReleaseUser(userp);
3317 return CM_ERROR_ISDIR;
3319 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3320 cm_ReleaseSCache(scp);
3321 cm_ReleaseUser(userp);
3323 return CM_ERROR_NOTDIR;
3326 /* open the file itself */
3327 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3329 /* save a pointer to the vnode */
3332 fidp->flags = fidflags;
3334 /* save parent dir and pathname for delete or change notification */
3335 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3336 fidp->flags |= SMB_FID_NTOPEN;
3337 fidp->NTopen_dscp = dscp;
3338 cm_HoldSCache(dscp);
3339 fidp->NTopen_pathp = strdup(lastNamep);
3341 fidp->NTopen_wholepathp = realPathp;
3343 /* we don't need this any longer */
3344 if (dscp) cm_ReleaseSCache(dscp);
3345 cm_Open(scp, 0, userp);
3347 /* set inp->fid so that later read calls in same msg can find fid */
3348 inp->fid = fidp->fid;
3352 lock_ObtainMutex(&scp->mx);
3353 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3354 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3355 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3356 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3357 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3358 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3359 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3360 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3361 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3363 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3364 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3365 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3366 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3367 smb_SetSMBParmByte(outp, parmSlot,
3368 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3369 lock_ReleaseMutex(&scp->mx);
3370 smb_SetSMBDataLength(outp, 0);
3372 osi_Log2(afsd_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3373 osi_LogSaveString(afsd_logp, realPathp));
3375 smb_ReleaseFID(fidp);
3377 cm_ReleaseUser(userp);
3379 /* leave scp held since we put it in fidp->scp */
3384 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3385 * Instead, ultimately, would like to use a subroutine for common code.
3387 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3389 char *pathp, *realPathp;
3393 cm_scache_t *dscp; /* parent dir */
3394 cm_scache_t *scp; /* file to create or open */
3397 unsigned long nameLength;
3399 unsigned int requestOpLock;
3400 unsigned int requestBatchOpLock;
3401 unsigned int mustBeDir;
3403 unsigned int desiredAccess;
3404 unsigned int extAttributes;
3405 unsigned int createDisp;
3406 unsigned int createOptions;
3407 int initialModeBits;
3408 unsigned short baseFid;
3409 smb_fid_t *baseFidp;
3411 cm_scache_t *baseDirp;
3412 unsigned short openAction;
3418 int parmOffset, dataOffset;
3429 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3430 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3431 parmp = inp->data + parmOffset;
3432 lparmp = (ULONG *) parmp;
3435 requestOpLock = flags & 0x02;
3436 requestBatchOpLock = flags & 0x04;
3437 mustBeDir = flags & 0x08;
3439 * Why all of a sudden 32-bit FID?
3440 * We will reject all bits higher than 16.
3442 if (lparmp[1] & 0xFFFF0000)
3443 return CM_ERROR_INVAL;
3444 baseFid = (unsigned short)lparmp[1];
3445 desiredAccess = lparmp[2];
3446 extAttributes = lparmp[5];
3447 createDisp = lparmp[7];
3448 createOptions = lparmp[8];
3449 nameLength = lparmp[11];
3451 /* mustBeDir is never set; createOptions directory bit seems to be
3454 if (createOptions & 1)
3456 else if (createOptions & 0x40)
3462 * compute initial mode bits based on read-only flag in
3463 * extended attributes
3465 initialModeBits = 0666;
3466 if (extAttributes & 1) initialModeBits &= ~0222;
3468 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3469 /* Sometimes path is not null-terminated, so we make a copy. */
3470 realPathp = malloc(nameLength+1);
3471 memcpy(realPathp, pathp, nameLength);
3472 realPathp[nameLength] = 0;
3474 spacep = cm_GetSpace();
3475 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3478 * Nothing here to handle SMB_IOCTL_FILENAME.
3479 * Will add it if necessary.
3482 userp = smb_GetUser(vcp, inp);
3485 baseDirp = cm_rootSCachep;
3486 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3489 baseFidp = smb_FindFID(vcp, baseFid, 0);
3490 baseDirp = baseFidp->scp;
3494 /* compute open mode */
3496 if (desiredAccess & DELETE)
3497 fidflags |= SMB_FID_OPENDELETE;
3498 if (desiredAccess & AFS_ACCESS_READ)
3499 fidflags |= SMB_FID_OPENREAD;
3500 if (desiredAccess & AFS_ACCESS_WRITE)
3501 fidflags |= SMB_FID_OPENWRITE;
3505 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3506 userp, tidPathp, &req, &scp);
3507 if (code == 0) foundscp = TRUE;
3509 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3510 /* look up parent directory */
3511 code = cm_NameI(baseDirp, spacep->data,
3512 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3513 userp, tidPathp, &req, &dscp);
3514 cm_FreeSpace(spacep);
3516 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3519 cm_ReleaseUser(userp);
3524 if (!lastNamep) lastNamep = realPathp;
3527 if (!smb_IsLegalFilename(lastNamep))
3528 return CM_ERROR_BADNTFILENAME;
3531 code = cm_Lookup(dscp, lastNamep,
3532 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3534 if (code && code != CM_ERROR_NOSUCHFILE) {
3535 cm_ReleaseSCache(dscp);
3536 cm_ReleaseUser(userp);
3543 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3544 cm_FreeSpace(spacep);
3547 /* if we get here, if code is 0, the file exists and is represented by
3548 * scp. Otherwise, we have to create it. The dir may be represented
3549 * by dscp, or we may have found the file directly. If code is non-zero,
3553 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3556 if (dscp) cm_ReleaseSCache(dscp);
3557 cm_ReleaseSCache(scp);
3558 cm_ReleaseUser(userp);
3563 if (createDisp == 2) {
3564 /* oops, file shouldn't be there */
3565 if (dscp) cm_ReleaseSCache(dscp);
3566 cm_ReleaseSCache(scp);
3567 cm_ReleaseUser(userp);
3569 return CM_ERROR_EXISTS;
3573 || createDisp == 5) {
3574 setAttr.mask = CM_ATTRMASK_LENGTH;
3575 setAttr.length.LowPart = 0;
3576 setAttr.length.HighPart = 0;
3577 code = cm_SetAttr(scp, &setAttr, userp, &req);
3578 openAction = 3; /* truncated existing file */
3580 else openAction = 1; /* found existing file */
3582 else if (createDisp == 1 || createDisp == 4) {
3583 /* don't create if not found */
3584 if (dscp) cm_ReleaseSCache(dscp);
3585 cm_ReleaseUser(userp);
3587 return CM_ERROR_NOSUCHFILE;
3589 else if (realDirFlag == 0 || realDirFlag == -1) {
3590 osi_assert(dscp != NULL);
3591 osi_Log1(afsd_logp, "smb_ReceiveNTTranCreate creating file %s",
3592 osi_LogSaveString(afsd_logp, lastNamep));
3593 openAction = 2; /* created file */
3594 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3595 setAttr.clientModTime = time(NULL);
3596 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3598 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3599 smb_NotifyChange(FILE_ACTION_ADDED,
3600 FILE_NOTIFY_CHANGE_FILE_NAME,
3601 dscp, lastNamep, NULL, TRUE);
3602 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3603 /* Not an exclusive create, and someone else tried
3604 * creating it already, then we open it anyway. We
3605 * don't bother retrying after this, since if this next
3606 * fails, that means that the file was deleted after we
3607 * started this call.
3609 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3612 if (createDisp == 5) {
3613 setAttr.mask = CM_ATTRMASK_LENGTH;
3614 setAttr.length.LowPart = 0;
3615 setAttr.length.HighPart = 0;
3616 code = cm_SetAttr(scp, &setAttr, userp,
3619 } /* lookup succeeded */
3623 /* create directory */
3624 osi_assert(dscp != NULL);
3626 "smb_ReceiveNTTranCreate creating directory %s",
3627 osi_LogSaveString(afsd_logp, lastNamep));
3628 openAction = 2; /* created directory */
3629 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3630 setAttr.clientModTime = time(NULL);
3631 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3632 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3633 smb_NotifyChange(FILE_ACTION_ADDED,
3634 FILE_NOTIFY_CHANGE_DIR_NAME,
3635 dscp, lastNamep, NULL, TRUE);
3637 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3638 /* Not an exclusive create, and someone else tried
3639 * creating it already, then we open it anyway. We
3640 * don't bother retrying after this, since if this next
3641 * fails, that means that the file was deleted after we
3642 * started this call.
3644 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3650 /* something went wrong creating or truncating the file */
3651 if (scp) cm_ReleaseSCache(scp);
3652 cm_ReleaseUser(userp);
3657 /* make sure we have file vs. dir right */
3658 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3659 cm_ReleaseSCache(scp);
3660 cm_ReleaseUser(userp);
3662 return CM_ERROR_ISDIR;
3664 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3665 cm_ReleaseSCache(scp);
3666 cm_ReleaseUser(userp);
3668 return CM_ERROR_NOTDIR;
3671 /* open the file itself */
3672 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3675 /* save a pointer to the vnode */
3678 fidp->flags = fidflags;
3680 /* save parent dir and pathname for deletion or change notification */
3681 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3682 fidp->flags |= SMB_FID_NTOPEN;
3683 fidp->NTopen_dscp = dscp;
3684 cm_HoldSCache(dscp);
3685 fidp->NTopen_pathp = strdup(lastNamep);
3687 fidp->NTopen_wholepathp = realPathp;
3689 /* we don't need this any longer */
3690 if (dscp) cm_ReleaseSCache(dscp);
3692 cm_Open(scp, 0, userp);
3694 /* set inp->fid so that later read calls in same msg can find fid */
3695 inp->fid = fidp->fid;
3698 parmOffset = 8*4 + 39;
3699 parmOffset += 1; /* pad to 4 */
3700 dataOffset = parmOffset + 70;
3704 /* Total Parameter Count */
3705 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3706 /* Total Data Count */
3707 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3708 /* Parameter Count */
3709 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3710 /* Parameter Offset */
3711 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3712 /* Parameter Displacement */
3713 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3715 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3717 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3718 /* Data Displacement */
3719 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3720 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
3721 smb_SetSMBDataLength(outp, 70);
3723 lock_ObtainMutex(&scp->mx);
3724 outData = smb_GetSMBData(outp, NULL);
3725 outData++; /* round to get to parmOffset */
3726 *outData = 0; outData++; /* oplock */
3727 *outData = 0; outData++; /* reserved */
3728 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
3729 *((ULONG *)outData) = openAction; outData += 4;
3730 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
3731 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3732 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
3733 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
3734 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
3735 *((FILETIME *)outData) = ft; outData += 8; /* change time */
3736 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
3737 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
3738 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
3739 *((USHORT *)outData) = 0; outData += 2; /* filetype */
3740 *((USHORT *)outData) = 0; outData += 2; /* dev state */
3741 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
3742 outData += 2; /* is a dir? */
3743 lock_ReleaseMutex(&scp->mx);
3745 osi_Log1(afsd_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
3747 smb_ReleaseFID(fidp);
3749 cm_ReleaseUser(userp);
3751 /* leave scp held since we put it in fidp->scp */
3755 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
3758 smb_packet_t *savedPacketp;
3759 ULONG filter; USHORT fid, watchtree;
3763 filter = smb_GetSMBParm(inp, 19)
3764 | (smb_GetSMBParm(inp, 20) << 16);
3765 fid = smb_GetSMBParm(inp, 21);
3766 watchtree = smb_GetSMBParm(inp, 22) && 0xffff;
3768 savedPacketp = smb_CopyPacket(inp);
3769 savedPacketp->vcp = vcp;
3770 lock_ObtainMutex(&smb_Dir_Watch_Lock);
3771 savedPacketp->nextp = smb_Directory_Watches;
3772 smb_Directory_Watches = savedPacketp;
3773 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
3775 fidp = smb_FindFID(vcp, fid, 0);
3777 osi_Log4(afsd_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
3778 filter, fid, watchtree, osi_LogSaveString(afsd_logp, fidp->NTopen_wholepathp));
3781 lock_ObtainMutex(&scp->mx);
3783 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
3785 scp->flags |= CM_SCACHEFLAG_WATCHED;
3786 lock_ReleaseMutex(&scp->mx);
3787 smb_ReleaseFID(fidp);
3789 outp->flags |= SMB_PACKETFLAG_NOSEND;
3794 unsigned char nullSecurityDesc[36] = {
3795 0x01, /* security descriptor revision */
3796 0x00, /* reserved, should be zero */
3797 0x00, 0x80, /* security descriptor control;
3798 * 0x8000 : self-relative format */
3799 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
3800 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
3801 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
3802 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
3803 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3804 /* "null SID" owner SID */
3805 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
3806 /* "null SID" group SID */
3809 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3811 int parmOffset, parmCount, dataOffset, dataCount;
3819 ULONG securityInformation;
3821 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3822 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3823 parmp = inp->data + parmOffset;
3824 sparmp = (USHORT *) parmp;
3825 lparmp = (ULONG *) parmp;
3828 securityInformation = lparmp[1];
3830 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
3831 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3839 parmOffset = 8*4 + 39;
3840 parmOffset += 1; /* pad to 4 */
3842 dataOffset = parmOffset + parmCount;
3846 /* Total Parameter Count */
3847 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
3848 /* Total Data Count */
3849 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
3850 /* Parameter Count */
3851 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
3852 /* Parameter Offset */
3853 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3854 /* Parameter Displacement */
3855 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3857 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
3859 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3860 /* Data Displacement */
3861 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3862 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
3863 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
3865 outData = smb_GetSMBData(outp, NULL);
3866 outData++; /* round to get to parmOffset */
3867 *((ULONG *)outData) = 36; outData += 4; /* length */
3869 if (maxData >= 36) {
3870 memcpy(outData, nullSecurityDesc, 36);
3874 return CM_ERROR_BUFFERTOOSMALL;
3877 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3879 unsigned short function;
3881 function = smb_GetSMBParm(inp, 18);
3883 osi_Log1(afsd_logp, "SMB NT Transact function %d", function);
3885 /* We can handle long names */
3886 if (vcp->flags & SMB_VCFLAG_USENT)
3887 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3891 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
3893 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
3895 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
3897 default: return CM_ERROR_INVAL;
3902 * smb_NotifyChange -- find relevant change notification messages and
3905 * If we don't know the file name (i.e. a callback break), filename is
3906 * NULL, and we return a zero-length list.
3908 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
3909 cm_scache_t *dscp, char *filename, char *otherFilename,
3910 BOOL isDirectParent)
3912 smb_packet_t *watch, *lastWatch, *nextWatch;
3913 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
3914 char *outData, *oldOutData;
3918 BOOL twoEntries = FALSE;
3919 ULONG otherNameLen, oldParmCount = 0;
3924 /* Get ready for rename within directory */
3925 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
3927 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
3930 lock_ObtainMutex(&smb_Dir_Watch_Lock);
3931 watch = smb_Directory_Watches;
3933 filter = smb_GetSMBParm(watch, 19)
3934 | (smb_GetSMBParm(watch, 20) << 16);
3935 fid = smb_GetSMBParm(watch, 21);
3936 wtree = smb_GetSMBParm(watch, 22) & 0xffff;
3937 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
3938 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
3942 * Strange hack - bug in NT Client and NT Server that we
3945 if (filter == 3 && wtree)
3948 fidp = smb_FindFID(vcp, fid, 0);
3949 if (fidp->scp != dscp
3950 || (filter & notifyFilter) == 0
3951 || (!isDirectParent && !wtree)) {
3952 smb_ReleaseFID(fidp);
3954 watch = watch->nextp;
3957 smb_ReleaseFID(fidp);
3960 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
3961 fid, filter, wtree, osi_LogSaveString(afsd_logp, filename));
3963 nextWatch = watch->nextp;
3964 if (watch == smb_Directory_Watches)
3965 smb_Directory_Watches = nextWatch;
3967 lastWatch->nextp = nextWatch;
3969 /* Turn off WATCHED flag in dscp */
3970 lock_ObtainMutex(&dscp->mx);
3972 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
3974 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
3975 lock_ReleaseMutex(&dscp->mx);
3977 /* Convert to response packet */
3978 ((smb_t *) watch)->reb = 0x80;
3979 ((smb_t *) watch)->wct = 0;
3982 if (filename == NULL)
3985 nameLen = strlen(filename);
3986 parmCount = 3*4 + nameLen*2;
3987 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
3989 otherNameLen = strlen(otherFilename);
3990 oldParmCount = parmCount;
3991 parmCount += 3*4 + otherNameLen*2;
3992 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
3994 if (maxLen < parmCount)
3995 parmCount = 0; /* not enough room */
3997 parmOffset = 8*4 + 39;
3998 parmOffset += 1; /* pad to 4 */
3999 dataOffset = parmOffset + parmCount;
4003 /* Total Parameter Count */
4004 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4005 /* Total Data Count */
4006 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4007 /* Parameter Count */
4008 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4009 /* Parameter Offset */
4010 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
4011 /* Parameter Displacement */
4012 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4014 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4016 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
4017 /* Data Displacement */
4018 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4019 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
4020 smb_SetSMBDataLength(watch, parmCount + 1);
4022 if (parmCount != 0) {
4023 outData = smb_GetSMBData(watch, NULL);
4024 outData++; /* round to get to parmOffset */
4025 oldOutData = outData;
4026 *((DWORD *)outData) = oldParmCount; outData += 4;
4027 /* Next Entry Offset */
4028 *((DWORD *)outData) = action; outData += 4;
4030 *((DWORD *)outData) = nameLen*2; outData += 4;
4031 /* File Name Length */
4032 mbstowcs((WCHAR *)outData, filename, nameLen);
4035 outData = oldOutData + oldParmCount;
4036 *((DWORD *)outData) = 0; outData += 4;
4037 /* Next Entry Offset */
4038 *((DWORD *)outData) = otherAction; outData += 4;
4040 *((DWORD *)outData) = otherNameLen*2;
4041 outData += 4; /* File Name Length */
4042 mbstowcs((WCHAR *)outData, otherFilename,
4043 otherNameLen); /* File Name */
4048 * If filename is null, we don't know the cause of the
4049 * change notification. We return zero data (see above),
4050 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
4051 * (= 0x010C). We set the error code here by hand, without
4052 * modifying wct and bcc.
4054 if (filename == NULL) {
4055 ((smb_t *) watch)->rcls = 0x0C;
4056 ((smb_t *) watch)->reh = 0x01;
4057 ((smb_t *) watch)->errLow = 0;
4058 ((smb_t *) watch)->errHigh = 0;
4059 /* Set NT Status codes flag */
4060 ((smb_t *) watch)->flg2 |= 0x4000;
4063 smb_SendPacket(vcp, watch);
4064 smb_FreePacket(watch);
4067 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4070 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4072 unsigned char *replyWctp;
4073 smb_packet_t *watch, *lastWatch;
4074 USHORT fid, watchtree;
4078 osi_Log0(afsd_logp, "SMB3 receive NT cancel");
4080 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4081 watch = smb_Directory_Watches;
4083 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
4084 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
4085 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
4086 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
4087 if (watch == smb_Directory_Watches)
4088 smb_Directory_Watches = watch->nextp;
4090 lastWatch->nextp = watch->nextp;
4091 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4093 /* Turn off WATCHED flag in scp */
4094 fid = smb_GetSMBParm(watch, 21);
4095 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
4097 fidp = smb_FindFID(vcp, fid, 0);
4099 osi_Log3(afsd_logp, "Cancelling change notification for fid %d wtree %d file %s",
4101 osi_LogSaveString(afsd_logp, fidp->NTopen_wholepathp));
4104 lock_ObtainMutex(&scp->mx);
4106 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4108 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
4109 lock_ReleaseMutex(&scp->mx);
4110 smb_ReleaseFID(fidp);
4112 /* assume STATUS32; return 0xC0000120 (CANCELED) */
4113 replyWctp = watch->wctp;
4117 ((smb_t *)watch)->rcls = 0x20;
4118 ((smb_t *)watch)->reh = 0x1;
4119 ((smb_t *)watch)->errLow = 0;
4120 ((smb_t *)watch)->errHigh = 0xC0;
4121 ((smb_t *)watch)->flg2 |= 0x4000;
4122 smb_SendPacket(vcp, watch);
4123 smb_FreePacket(watch);
4127 watch = watch->nextp;
4129 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4136 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");