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
12 #include <afs/param.h>
30 extern smb_vc_t *dead_vcp;
32 extern osi_hyper_t hzero;
34 smb_packet_t *smb_Directory_Watches = NULL;
35 osi_mutex_t smb_Dir_Watch_Lock;
37 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
39 /* protected by the smb_globalLock */
40 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
42 /* retrieve a held reference to a user structure corresponding to an incoming
44 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
49 uidp = smb_FindUID(vcp, inp->uid, 0);
50 if (!uidp) return NULL;
52 lock_ObtainMutex(&uidp->mx);
54 up = uidp->unp->userp;
57 lock_ReleaseMutex(&uidp->mx);
65 * Return extended attributes.
66 * Right now, we aren't using any of the "new" bits, so this looks exactly
67 * like smb_Attributes() (see smb.c).
69 unsigned long smb_ExtAttributes(cm_scache_t *scp)
73 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
74 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
79 * We used to mark a file RO if it was in an RO volume, but that
80 * turns out to be impolitic in NT. See defect 10007.
83 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
85 if ((scp->unixModeBits & 0222) == 0)
86 attrs |= 1; /* Read-only */
89 attrs = 0x80; /* FILE_ATTRIBUTE_NORMAL */
94 int smb_V3IsStarMask(char *maskp)
99 if (tc == '?' || tc == '*') return 1;
103 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
106 /* skip over null-terminated string */
107 *chainpp = inp + strlen(inp) + 1;
112 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
115 char *usern, *pwd, *pwdx;
116 smb_user_t *uidp, *dead_uidp;
117 unsigned short newUid;
123 /* Check for bad conns */
124 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
125 return CM_ERROR_REMOTECONN;
127 /* For NT LM 0.12 and up, get capabilities */
128 if (vcp->flags & SMB_VCFLAG_USENT) {
129 caps = smb_GetSMBParm(inp, 11);
131 vcp->flags |= SMB_VCFLAG_STATUS32;
132 /* for now, ignore other capability bits */
136 tp = smb_GetSMBData(inp, NULL);
137 if (vcp->flags & SMB_VCFLAG_USENT)
138 pwdx = smb_ParseString(tp, &tp);
139 pwd = smb_ParseString(tp, &tp);
140 usern = smb_ParseString(tp, &tp);
142 /* On Windows 2000, this function appears to be called more often than
143 it is expected to be called. This resulted in multiple smb_user_t
144 records existing all for the same user session which results in all
145 of the users tokens disappearing.
147 To avoid this problem, we look for an existing smb_user_t record
148 based on the users name, and use that one if we find it.
151 uidp = smb_FindUserByNameThisSession(vcp, usern);
152 if (uidp) { /* already there, so don't create a new one */
155 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
156 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,usern);
157 osi_Log3(afsd_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
158 smb_ReleaseUID(uidp);
161 /* do a global search for the username/machine name pair */
162 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
164 /* Create a new UID and cm_user_t structure */
167 userp = cm_NewUser();
168 lock_ObtainMutex(&vcp->mx);
169 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
170 lock_ReleaseMutex(&vcp->mx);
172 /* Create a new smb_user_t structure and connect them up */
173 lock_ObtainMutex(&unp->mx);
175 lock_ReleaseMutex(&unp->mx);
177 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
178 lock_ObtainMutex(&uidp->mx);
180 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",vcp,vcp->lana,vcp->lsn,newUid,usern);
181 osi_Log4(afsd_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
182 lock_ReleaseMutex(&uidp->mx);
183 smb_ReleaseUID(uidp);
186 /* Return UID to the client */
187 ((smb_t *)outp)->uid = newUid;
188 /* Also to the next chained message */
189 ((smb_t *)inp)->uid = newUid;
191 osi_Log3(afsd_logp, "SMB3 session setup name %s creating ID %d%s",
192 osi_LogSaveString(afsd_logp, usern), newUid, osi_LogSaveString(afsd_logp, s1));
193 smb_SetSMBParm(outp, 2, 0);
194 smb_SetSMBDataLength(outp, 0);
198 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
202 /* don't get tokens from this VC */
203 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
205 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
207 /* find the tree and free it */
208 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
210 char *s1 = NULL, *s2 = NULL;
212 if (s2 == NULL) s2 = " ";
213 if (s1 == NULL) {s1 = s2; s2 = " ";}
215 osi_Log4(afsd_logp, "SMB3 user logoffX uid %d name %s%s%s",
217 osi_LogSaveString(afsd_logp,
218 (uidp->unp) ? uidp->unp->name: " "), s1, s2);
220 lock_ObtainMutex(&uidp->mx);
221 uidp->flags |= SMB_USERFLAG_DELETE;
223 * it doesn't get deleted right away
224 * because the vcp points to it
226 lock_ReleaseMutex(&uidp->mx);
229 osi_Log0(afsd_logp, "SMB3 user logoffX");
231 smb_SetSMBDataLength(outp, 0);
235 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
238 unsigned short newTid;
248 osi_Log0(afsd_logp, "SMB3 receive tree connect");
250 /* parse input parameters */
251 tp = smb_GetSMBData(inp, NULL);
252 passwordp = smb_ParseString(tp, &tp);
253 pathp = smb_ParseString(tp, &tp);
254 servicep = smb_ParseString(tp, &tp);
256 tp = strrchr(pathp, '\\');
258 return CM_ERROR_BADSMB;
260 strcpy(shareName, tp+1);
262 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0)
263 return CM_ERROR_NOIPC;
265 userp = smb_GetUser(vcp, inp);
267 lock_ObtainMutex(&vcp->mx);
268 newTid = vcp->tidCounter++;
269 lock_ReleaseMutex(&vcp->mx);
271 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
272 shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
274 smb_ReleaseTID(tidp);
275 return CM_ERROR_BADSHARENAME;
277 lock_ObtainMutex(&tidp->mx);
279 tidp->pathname = sharePath;
280 lock_ReleaseMutex(&tidp->mx);
281 smb_ReleaseTID(tidp);
283 if (vcp->flags & SMB_VCFLAG_USENT)
284 smb_SetSMBParm(outp, 2, 0); /* OptionalSupport bits */
286 ((smb_t *)outp)->tid = newTid;
287 ((smb_t *)inp)->tid = newTid;
288 tp = smb_GetSMBData(outp, NULL);
292 smb_SetSMBDataLength(outp, 3);
294 osi_Log1(afsd_logp, "SMB3 tree connect created ID %d", newTid);
298 /* must be called with global tran lock held */
299 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
301 smb_tran2Packet_t *tp;
304 smbp = (smb_t *) inp->data;
305 for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
306 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
312 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
313 int totalParms, int totalData)
315 smb_tran2Packet_t *tp;
318 smbp = (smb_t *) inp->data;
319 tp = malloc(sizeof(*tp));
320 memset(tp, 0, sizeof(*tp));
323 tp->curData = tp->curParms = 0;
324 tp->totalData = totalData;
325 tp->totalParms = totalParms;
330 tp->res[0] = smbp->res[0];
331 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
332 tp->opcode = smb_GetSMBParm(inp, 14);
334 tp->parmsp = malloc(totalParms);
336 tp->datap = malloc(totalData);
337 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
341 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
342 smb_tran2Packet_t *inp, smb_packet_t *outp,
343 int totalParms, int totalData)
345 smb_tran2Packet_t *tp;
346 unsigned short parmOffset;
347 unsigned short dataOffset;
348 unsigned short dataAlign;
350 tp = malloc(sizeof(*tp));
351 memset(tp, 0, sizeof(*tp));
353 tp->curData = tp->curParms = 0;
354 tp->totalData = totalData;
355 tp->totalParms = totalParms;
356 tp->oldTotalParms = totalParms;
361 tp->res[0] = inp->res[0];
362 tp->opcode = inp->opcode;
365 * We calculate where the parameters and data will start.
366 * This calculation must parallel the calculation in
367 * smb_SendTran2Packet.
370 parmOffset = 10*2 + 35;
371 parmOffset++; /* round to even */
372 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
374 dataOffset = parmOffset + totalParms;
375 dataAlign = dataOffset & 2; /* quad-align */
376 dataOffset += dataAlign;
377 tp->datap = outp->data + dataOffset;
382 /* free a tran2 packet; must be called with smb_globalLock held */
383 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
385 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
386 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
395 /* called with a VC, an input packet to respond to, and an error code.
396 * sends an error response.
398 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
399 smb_packet_t *tp, long code)
402 unsigned short errCode;
403 unsigned char errClass;
404 unsigned long NTStatus;
406 if (vcp->flags & SMB_VCFLAG_STATUS32)
407 smb_MapNTError(code, &NTStatus);
409 smb_MapCoreError(code, vcp, &errCode, &errClass);
411 smb_FormatResponsePacket(vcp, NULL, tp);
414 /* We can handle long names */
415 if (vcp->flags & SMB_VCFLAG_USENT)
416 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
418 /* now copy important fields from the tran 2 packet */
419 smbp->com = 0x32; /* tran 2 response */
420 smbp->tid = t2p->tid;
421 smbp->mid = t2p->mid;
422 smbp->pid = t2p->pid;
423 smbp->uid = t2p->uid;
424 smbp->res[0] = t2p->res[0];
425 if (vcp->flags & SMB_VCFLAG_STATUS32) {
426 smbp->rcls = (unsigned char) (NTStatus & 0xff);
427 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
428 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
429 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
430 smbp->flg2 |= 0x4000;
433 smbp->rcls = errClass;
434 smbp->errLow = (unsigned char) (errCode & 0xff);
435 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
439 smb_SendPacket(vcp, tp);
442 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
445 unsigned short parmOffset;
446 unsigned short dataOffset;
447 unsigned short totalLength;
448 unsigned short dataAlign;
451 smb_FormatResponsePacket(vcp, NULL, tp);
454 /* We can handle long names */
455 if (vcp->flags & SMB_VCFLAG_USENT)
456 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
458 /* now copy important fields from the tran 2 packet */
459 smbp->com = 0x32; /* tran 2 response */
460 smbp->tid = t2p->tid;
461 smbp->mid = t2p->mid;
462 smbp->pid = t2p->pid;
463 smbp->uid = t2p->uid;
464 smbp->res[0] = t2p->res[0];
466 totalLength = 1 + t2p->totalData + t2p->totalParms;
468 /* now add the core parameters (tran2 info) to the packet */
469 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
470 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
471 smb_SetSMBParm(tp, 2, 0); /* reserved */
472 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
473 parmOffset = 10*2 + 35; /* parm offset in packet */
474 parmOffset++; /* round to even */
475 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
476 * hdr, bcc and wct */
477 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
478 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
479 dataOffset = parmOffset + t2p->oldTotalParms;
480 dataAlign = dataOffset & 2; /* quad-align */
481 dataOffset += dataAlign;
482 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
483 smb_SetSMBParm(tp, 8, 0); /* data displacement */
484 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
487 datap = smb_GetSMBData(tp, NULL);
488 *datap++ = 0; /* we rounded to even */
490 totalLength += dataAlign;
491 smb_SetSMBDataLength(tp, totalLength);
493 /* next, send the datagram */
494 smb_SendPacket(vcp, tp);
497 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
499 smb_tran2Packet_t *asp;
511 /* We sometimes see 0 word count. What to do? */
512 if (*inp->wctp == 0) {
517 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0");
519 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
520 ptbuf[0] = "Transaction2 word count = 0";
521 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
522 1, inp->ncb_length, ptbuf, inp);
523 DeregisterEventSource(h);
525 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0");
528 smb_SetSMBDataLength(outp, 0);
529 smb_SendPacket(vcp, outp);
533 totalParms = smb_GetSMBParm(inp, 0);
534 totalData = smb_GetSMBParm(inp, 1);
536 firstPacket = (inp->inCom == 0x32);
538 /* find the packet we're reassembling */
539 lock_ObtainWrite(&smb_globalLock);
540 asp = smb_FindTran2Packet(vcp, inp);
542 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
544 lock_ReleaseWrite(&smb_globalLock);
546 /* now merge in this latest packet; start by looking up offsets */
548 parmDisp = dataDisp = 0;
549 parmOffset = smb_GetSMBParm(inp, 10);
550 dataOffset = smb_GetSMBParm(inp, 12);
551 parmCount = smb_GetSMBParm(inp, 9);
552 dataCount = smb_GetSMBParm(inp, 11);
553 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
554 asp->maxReturnData = smb_GetSMBParm(inp, 3);
556 osi_Log3(afsd_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
557 totalData, dataCount, asp->maxReturnData);
560 parmDisp = smb_GetSMBParm(inp, 4);
561 parmOffset = smb_GetSMBParm(inp, 3);
562 dataDisp = smb_GetSMBParm(inp, 7);
563 dataOffset = smb_GetSMBParm(inp, 6);
564 parmCount = smb_GetSMBParm(inp, 2);
565 dataCount = smb_GetSMBParm(inp, 5);
567 osi_Log2(afsd_logp, "SMB3 received T2 aux packet parms %d, data %d",
568 parmCount, dataCount);
571 /* now copy the parms and data */
572 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
573 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
575 /* account for new bytes */
576 asp->curData += dataCount;
577 asp->curParms += parmCount;
579 /* finally, if we're done, remove the packet from the queue and dispatch it */
580 if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
581 /* we've received it all */
582 lock_ObtainWrite(&smb_globalLock);
583 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
584 lock_ReleaseWrite(&smb_globalLock);
586 /* now dispatch it */
587 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",vcp,vcp->lana,vcp->lsn);
588 osi_Log4(afsd_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
589 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
591 /* if an error is returned, we're supposed to send an error packet,
592 * otherwise the dispatched function already did the data sending.
593 * We give dispatched proc the responsibility since it knows how much
597 smb_SendTran2Error(vcp, asp, outp, code);
600 /* free the input tran 2 packet */
601 lock_ObtainWrite(&smb_globalLock);
602 smb_FreeTran2Packet(asp);
603 lock_ReleaseWrite(&smb_globalLock);
605 else if (firstPacket) {
606 /* the first packet in a multi-packet request, we need to send an
607 * ack to get more data.
609 smb_SetSMBDataLength(outp, 0);
610 smb_SendPacket(vcp, outp);
616 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
619 smb_tran2Packet_t *outp;
624 cm_scache_t *dscp; /* dir we're dealing with */
625 cm_scache_t *scp; /* file we're creating */
637 int parmSlot; /* which parm we're dealing with */
646 extraInfo = (p->parmsp[0] & 1); /* return extra info */
647 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
649 openFun = p->parmsp[6]; /* open function */
650 excl = ((openFun & 3) == 0);
651 trunc = ((openFun & 3) == 2); /* truncate it */
652 openMode = (p->parmsp[1] & 0x7);
653 openAction = 0; /* tracks what we did */
655 attributes = p->parmsp[3];
656 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
658 /* compute initial mode bits based on read-only flag in attributes */
659 initialModeBits = 0666;
660 if (attributes & 1) initialModeBits &= ~0222;
662 pathp = (char *) (&p->parmsp[14]);
664 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
666 spacep = cm_GetSpace();
667 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
669 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
670 /* special case magic file name for receiving IOCTL requests
671 * (since IOCTL calls themselves aren't getting through).
673 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
674 smb_SetupIoctlFid(fidp, spacep);
676 /* copy out remainder of the parms */
678 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
680 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
681 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
682 outp->parmsp[parmSlot] = 0; parmSlot++;
683 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
684 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
685 outp->parmsp[parmSlot] = openMode; parmSlot++;
686 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
687 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
689 /* and the final "always present" stuff */
690 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
691 /* next write out the "unique" ID */
692 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
693 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
694 outp->parmsp[parmSlot] = 0; parmSlot++;
695 if (returnEALength) {
696 outp->parmsp[parmSlot] = 0; parmSlot++;
697 outp->parmsp[parmSlot] = 0; parmSlot++;
701 outp->totalParms = parmSlot * 2;
703 smb_SendTran2Packet(vcp, outp, op);
705 smb_FreeTran2Packet(outp);
707 /* and clean up fid reference */
708 smb_ReleaseFID(fidp);
712 userp = smb_GetTran2User(vcp, p);
713 tidPathp = smb_GetTIDPath(vcp, p->tid);
716 code = cm_NameI(cm_rootSCachep, pathp,
717 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
718 userp, tidPathp, &req, &scp);
720 code = cm_NameI(cm_rootSCachep, spacep->data,
721 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
722 userp, tidPathp, &req, &dscp);
723 cm_FreeSpace(spacep);
726 cm_ReleaseUser(userp);
727 smb_FreeTran2Packet(outp);
731 /* otherwise, scp points to the parent directory. Do a lookup,
732 * and truncate the file if we find it, otherwise we create the
735 if (!lastNamep) lastNamep = pathp;
737 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
739 if (code && code != CM_ERROR_NOSUCHFILE) {
740 cm_ReleaseSCache(dscp);
741 cm_ReleaseUser(userp);
742 smb_FreeTran2Packet(outp);
747 cm_FreeSpace(spacep);
750 /* if we get here, if code is 0, the file exists and is represented by
751 * scp. Otherwise, we have to create it.
754 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
756 if (dscp) cm_ReleaseSCache(dscp);
757 cm_ReleaseSCache(scp);
758 cm_ReleaseUser(userp);
759 smb_FreeTran2Packet(outp);
764 /* oops, file shouldn't be there */
765 if (dscp) cm_ReleaseSCache(dscp);
766 cm_ReleaseSCache(scp);
767 cm_ReleaseUser(userp);
768 smb_FreeTran2Packet(outp);
769 return CM_ERROR_EXISTS;
773 setAttr.mask = CM_ATTRMASK_LENGTH;
774 setAttr.length.LowPart = 0;
775 setAttr.length.HighPart = 0;
776 code = cm_SetAttr(scp, &setAttr, userp, &req);
777 openAction = 3; /* truncated existing file */
779 else openAction = 1; /* found existing file */
781 else if (!(openFun & 0x10)) {
782 /* don't create if not found */
783 if (dscp) cm_ReleaseSCache(dscp);
784 osi_assert(scp == NULL);
785 cm_ReleaseUser(userp);
786 smb_FreeTran2Packet(outp);
787 return CM_ERROR_NOSUCHFILE;
790 osi_assert(dscp != NULL && scp == NULL);
791 openAction = 2; /* created file */
792 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
793 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
794 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
796 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
797 smb_NotifyChange(FILE_ACTION_ADDED,
798 FILE_NOTIFY_CHANGE_FILE_NAME,
799 dscp, lastNamep, NULL, TRUE);
800 if (!excl && code == CM_ERROR_EXISTS) {
801 /* not an exclusive create, and someone else tried
802 * creating it already, then we open it anyway. We
803 * don't bother retrying after this, since if this next
804 * fails, that means that the file was deleted after we
807 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
811 setAttr.mask = CM_ATTRMASK_LENGTH;
812 setAttr.length.LowPart = 0;
813 setAttr.length.HighPart = 0;
814 code = cm_SetAttr(scp, &setAttr, userp,
817 } /* lookup succeeded */
821 /* we don't need this any longer */
822 if (dscp) cm_ReleaseSCache(dscp);
825 /* something went wrong creating or truncating the file */
826 if (scp) cm_ReleaseSCache(scp);
827 cm_ReleaseUser(userp);
828 smb_FreeTran2Packet(outp);
832 /* make sure we're about to open a file */
833 if (scp->fileType != CM_SCACHETYPE_FILE) {
834 cm_ReleaseSCache(scp);
835 cm_ReleaseUser(userp);
836 smb_FreeTran2Packet(outp);
837 return CM_ERROR_ISDIR;
840 /* now all we have to do is open the file itself */
841 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
844 /* save a pointer to the vnode */
847 /* compute open mode */
848 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
849 if (openMode == 1 || openMode == 2)
850 fidp->flags |= SMB_FID_OPENWRITE;
852 smb_ReleaseFID(fidp);
854 cm_Open(scp, 0, userp);
856 /* copy out remainder of the parms */
858 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
859 lock_ObtainMutex(&scp->mx);
861 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
862 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
863 outp->parmsp[parmSlot] = dosTime & 0xffff; parmSlot++;
864 outp->parmsp[parmSlot] = (dosTime>>16) & 0xffff; parmSlot++;
865 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
867 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
869 outp->parmsp[parmSlot] = openMode; parmSlot++;
870 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
871 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
873 /* and the final "always present" stuff */
874 outp->parmsp[parmSlot] = openAction; parmSlot++;
875 /* next write out the "unique" ID */
876 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
877 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
878 outp->parmsp[parmSlot] = 0; parmSlot++;
879 if (returnEALength) {
880 outp->parmsp[parmSlot] = 0; parmSlot++;
881 outp->parmsp[parmSlot] = 0; parmSlot++;
883 lock_ReleaseMutex(&scp->mx);
884 outp->totalData = 0; /* total # of data bytes */
885 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
887 smb_SendTran2Packet(vcp, outp, op);
889 smb_FreeTran2Packet(outp);
891 cm_ReleaseUser(userp);
892 /* leave scp held since we put it in fidp->scp */
896 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
898 return CM_ERROR_BADOP;
901 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
903 return CM_ERROR_BADOP;
906 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
908 smb_tran2Packet_t *outp;
909 smb_tran2QFSInfo_t qi;
912 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
914 osi_Log1(afsd_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
916 switch (p->parmsp[0]) {
917 case 1: responseSize = sizeof(qi.u.allocInfo); break;
918 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
919 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
920 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
921 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
922 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
923 default: return CM_ERROR_INVAL;
926 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
927 switch (p->parmsp[0]) {
930 qi.u.allocInfo.FSID = 0;
931 qi.u.allocInfo.sectorsPerAllocUnit = 1;
932 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
933 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
934 qi.u.allocInfo.bytesPerSector = 1024;
939 qi.u.volumeInfo.vsn = 1234;
940 qi.u.volumeInfo.vnCount = 4;
941 /* we're supposed to pad it out with zeroes to the end */
942 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
943 strcpy(qi.u.volumeInfo.label, "AFS");
948 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
949 qi.u.FSvolumeInfo.vsn = 1234;
950 qi.u.FSvolumeInfo.vnCount = 4;
951 strcpy(qi.u.FSvolumeInfo.label, "AFS");
957 temp.LowPart = 0x7fffffff;
958 qi.u.FSsizeInfo.totalAllocUnits = temp;
959 temp.LowPart = 0x3fffffff;
960 qi.u.FSsizeInfo.availAllocUnits = temp;
961 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
962 qi.u.FSsizeInfo.bytesPerSector = 1024;
967 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
968 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
972 /* FS attribute info */
973 /* attributes, defined in WINNT.H:
974 * FILE_CASE_SENSITIVE_SEARCH 0x1
975 * FILE_CASE_PRESERVED_NAMES 0x2
976 * <no name defined> 0x4000
977 * If bit 0x4000 is not set, Windows 95 thinks
978 * we can't handle long (non-8.3) names,
979 * despite our protestations to the contrary.
981 qi.u.FSattributeInfo.attributes = 0x4003;
982 qi.u.FSattributeInfo.maxCompLength = 255;
983 qi.u.FSattributeInfo.FSnameLength = 6;
984 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
988 /* copy out return data, and set corresponding sizes */
989 outp->totalParms = 0;
990 outp->totalData = responseSize;
991 memcpy(outp->datap, &qi, responseSize);
993 /* send and free the packets */
994 smb_SendTran2Packet(vcp, outp, op);
995 smb_FreeTran2Packet(outp);
1000 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1002 return CM_ERROR_BADOP;
1005 struct smb_ShortNameRock {
1009 size_t shortNameLen;
1012 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
1015 struct smb_ShortNameRock *rockp;
1019 /* compare both names and vnodes, though probably just comparing vnodes
1020 * would be safe enough.
1022 if (stricmp(dep->name, rockp->maskp) != 0)
1024 if (ntohl(dep->fid.vnode) != rockp->vnode)
1026 /* This is the entry */
1027 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1028 rockp->shortNameLen = shortNameEnd - rockp->shortName;
1029 return CM_ERROR_STOPNOW;
1032 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1033 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1035 struct smb_ShortNameRock rock;
1039 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1043 spacep = cm_GetSpace();
1044 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1046 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1048 cm_FreeSpace(spacep);
1049 if (code) return code;
1051 if (!lastNamep) lastNamep = pathp;
1054 thyper.HighPart = 0;
1055 rock.shortName = shortName;
1057 rock.maskp = lastNamep;
1058 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1061 cm_ReleaseSCache(dscp);
1064 return CM_ERROR_NOSUCHFILE;
1065 if (code == CM_ERROR_STOPNOW) {
1066 *shortNameLenp = rock.shortNameLen;
1072 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1074 smb_tran2Packet_t *outp;
1075 unsigned long dosTime;
1077 unsigned short infoLevel;
1079 unsigned short attributes;
1080 unsigned long extAttributes;
1085 cm_scache_t *scp, *dscp;
1094 infoLevel = p->parmsp[0];
1095 if (infoLevel == 6) nbytesRequired = 0;
1096 else if (infoLevel == 1) nbytesRequired = 22;
1097 else if (infoLevel == 2) nbytesRequired = 26;
1098 else if (infoLevel == 0x101) nbytesRequired = 40;
1099 else if (infoLevel == 0x102) nbytesRequired = 24;
1100 else if (infoLevel == 0x103) nbytesRequired = 4;
1101 else if (infoLevel == 0x108) nbytesRequired = 30;
1103 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1104 p->opcode, infoLevel);
1105 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1108 osi_Log2(afsd_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1109 osi_LogSaveString(afsd_logp, (char *)(&p->parmsp[3])));
1111 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1113 if (infoLevel > 0x100)
1114 outp->totalParms = 2;
1116 outp->totalParms = 0;
1117 outp->totalData = nbytesRequired;
1119 /* now, if we're at infoLevel 6, we're only being asked to check
1120 * the syntax, so we just OK things now. In particular, we're *not*
1121 * being asked to verify anything about the state of any parent dirs.
1123 if (infoLevel == 6) {
1124 smb_SendTran2Packet(vcp, outp, opx);
1125 smb_FreeTran2Packet(outp);
1129 userp = smb_GetTran2User(vcp, p);
1131 tidPathp = smb_GetTIDPath(vcp, p->tid);
1134 * XXX Strange hack XXX
1136 * As of Patch 7 (13 January 98), we are having the following problem:
1137 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1138 * requests to look up "desktop.ini" in all the subdirectories.
1139 * This can cause zillions of timeouts looking up non-existent cells
1140 * and volumes, especially in the top-level directory.
1142 * We have not found any way to avoid this or work around it except
1143 * to explicitly ignore the requests for mount points that haven't
1144 * yet been evaluated and for directories that haven't yet been
1147 if (infoLevel == 0x101) {
1148 spacep = cm_GetSpace();
1149 smb_StripLastComponent(spacep->data, &lastComp,
1150 (char *)(&p->parmsp[3]));
1151 /* Make sure that lastComp is not NULL */
1153 if (strcmp(lastComp, "\\desktop.ini") == 0) {
1154 code = cm_NameI(cm_rootSCachep, spacep->data,
1158 userp, tidPathp, &req, &dscp);
1160 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1161 && !dscp->mountRootFidp)
1162 code = CM_ERROR_NOSUCHFILE;
1163 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1164 cm_buf_t *bp = buf_Find(dscp, &hzero);
1168 code = CM_ERROR_NOSUCHFILE;
1170 cm_ReleaseSCache(dscp);
1172 cm_FreeSpace(spacep);
1173 cm_ReleaseUser(userp);
1174 smb_SendTran2Error(vcp, p, opx, code);
1175 smb_FreeTran2Packet(outp);
1180 cm_FreeSpace(spacep);
1183 /* now do namei and stat, and copy out the info */
1184 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1185 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1188 cm_ReleaseUser(userp);
1189 smb_SendTran2Error(vcp, p, opx, code);
1190 smb_FreeTran2Packet(outp);
1194 lock_ObtainMutex(&scp->mx);
1195 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1196 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1197 if (code) goto done;
1199 /* now we have the status in the cache entry, and everything is locked.
1200 * Marshall the output data.
1203 /* for info level 108, figure out short name */
1204 if (infoLevel == 0x108) {
1205 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1206 tidPathp, scp->fid.vnode, shortName,
1213 *((u_long *)op) = len * 2; op += 4;
1214 mbstowcs((unsigned short *)op, shortName, len);
1219 if (infoLevel == 1 || infoLevel == 2) {
1220 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1221 *((u_long *)op) = dosTime; op += 4; /* creation time */
1222 *((u_long *)op) = dosTime; op += 4; /* access time */
1223 *((u_long *)op) = dosTime; op += 4; /* write time */
1224 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1225 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1226 attributes = smb_Attributes(scp);
1227 *((u_short *)op) = attributes; op += 2; /* attributes */
1229 else if (infoLevel == 0x101) {
1230 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1231 *((FILETIME *)op) = ft; op += 8; /* creation time */
1232 *((FILETIME *)op) = ft; op += 8; /* last access time */
1233 *((FILETIME *)op) = ft; op += 8; /* last write time */
1234 *((FILETIME *)op) = ft; op += 8; /* last change time */
1235 extAttributes = smb_ExtAttributes(scp);
1236 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1237 *((u_long *)op) = 0; op += 4; /* don't know what this is */
1239 else if (infoLevel == 0x102) {
1240 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1241 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1242 *((u_long *)op) = scp->linkCount; op += 4;
1245 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1248 else if (infoLevel == 0x103) {
1249 memset(op, 0, 4); op += 4; /* EA size */
1252 /* now, if we are being asked about extended attrs, return a 0 size */
1253 if (infoLevel == 2) {
1254 *((u_long *)op) = 0; op += 4;
1258 /* send and free the packets */
1260 lock_ReleaseMutex(&scp->mx);
1261 cm_ReleaseSCache(scp);
1262 cm_ReleaseUser(userp);
1263 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1264 else smb_SendTran2Error(vcp, p, opx, code);
1265 smb_FreeTran2Packet(outp);
1270 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1272 return CM_ERROR_BADOP;
1275 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1277 smb_tran2Packet_t *outp;
1279 unsigned long attributes;
1280 unsigned short infoLevel;
1293 fidp = smb_FindFID(vcp, fid, 0);
1296 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
1300 infoLevel = p->parmsp[1];
1301 if (infoLevel == 0x101) nbytesRequired = 40;
1302 else if (infoLevel == 0x102) nbytesRequired = 24;
1303 else if (infoLevel == 0x103) nbytesRequired = 4;
1304 else if (infoLevel == 0x104) nbytesRequired = 6;
1306 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1307 p->opcode, infoLevel);
1308 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1311 osi_Log2(afsd_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1313 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1315 if (infoLevel > 0x100)
1316 outp->totalParms = 2;
1318 outp->totalParms = 0;
1319 outp->totalData = nbytesRequired;
1321 userp = smb_GetTran2User(vcp, p);
1324 lock_ObtainMutex(&scp->mx);
1325 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1326 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1327 if (code) goto done;
1329 /* now we have the status in the cache entry, and everything is locked.
1330 * Marshall the output data.
1333 if (infoLevel == 0x101) {
1334 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1335 *((FILETIME *)op) = ft; op += 8; /* creation time */
1336 *((FILETIME *)op) = ft; op += 8; /* last access time */
1337 *((FILETIME *)op) = ft; op += 8; /* last write time */
1338 *((FILETIME *)op) = ft; op += 8; /* last change time */
1339 attributes = smb_ExtAttributes(scp);
1340 *((u_long *)op) = attributes; op += 4;
1341 *((u_long *)op) = 0; op += 4;
1343 else if (infoLevel == 0x102) {
1344 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1345 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1346 *((u_long *)op) = scp->linkCount; op += 4;
1347 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1349 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1352 else if (infoLevel == 0x103) {
1353 *((u_long *)op) = 0; op += 4;
1355 else if (infoLevel == 0x104) {
1359 if (fidp->NTopen_wholepathp)
1360 name = fidp->NTopen_wholepathp;
1362 name = "\\"; /* probably can't happen */
1364 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
1365 *((u_long *)op) = len * 2; op += 4;
1366 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1369 /* send and free the packets */
1371 lock_ReleaseMutex(&scp->mx);
1372 cm_ReleaseUser(userp);
1373 smb_ReleaseFID(fidp);
1374 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1375 else smb_SendTran2Error(vcp, p, opx, code);
1376 smb_FreeTran2Packet(outp);
1381 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1386 unsigned short infoLevel;
1387 smb_tran2Packet_t *outp;
1395 fidp = smb_FindFID(vcp, fid, 0);
1398 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1402 infoLevel = p->parmsp[1];
1403 if (infoLevel > 0x104 || infoLevel < 0x101) {
1404 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1405 p->opcode, infoLevel);
1406 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1410 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1411 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1414 if ((infoLevel == 0x103 || infoLevel == 0x104)
1415 && !(fidp->flags & SMB_FID_OPENWRITE)) {
1416 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1420 osi_Log1(afsd_logp, "T2 SFileInfo type 0x%x", infoLevel);
1422 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1424 outp->totalParms = 2;
1425 outp->totalData = 0;
1427 userp = smb_GetTran2User(vcp, p);
1431 if (infoLevel == 0x101) {
1433 unsigned int attribute;
1436 /* lock the vnode with a callback; we need the current status
1437 * to determine what the new status is, in some cases.
1439 lock_ObtainMutex(&scp->mx);
1440 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1441 CM_SCACHESYNC_GETSTATUS
1442 | CM_SCACHESYNC_NEEDCALLBACK);
1444 lock_ReleaseMutex(&scp->mx);
1448 /* prepare for setattr call */
1451 lastMod = *((FILETIME *)(p->datap + 16));
1452 /* when called as result of move a b, lastMod is (-1, -1). If the check for -1 is not present, timestamp
1453 of the resulting file will be 1969 (-1)
1455 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
1456 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1457 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1459 fidp->flags |= SMB_FID_MTIMESETDONE;
1462 attribute = *((u_long *)(p->datap + 32));
1463 if (attribute != 0) {
1464 if ((scp->unixModeBits & 0222)
1465 && (attribute & 1) != 0) {
1466 /* make a writable file read-only */
1467 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1468 attr.unixModeBits = scp->unixModeBits & ~0222;
1470 else if ((scp->unixModeBits & 0222) == 0
1471 && (attribute & 1) == 0) {
1472 /* make a read-only file writable */
1473 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1474 attr.unixModeBits = scp->unixModeBits | 0222;
1477 lock_ReleaseMutex(&scp->mx);
1481 code = cm_SetAttr(scp, &attr, userp, &req);
1485 else if (infoLevel == 0x103 || infoLevel == 0x104) {
1486 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1489 attr.mask = CM_ATTRMASK_LENGTH;
1490 attr.length.LowPart = size.LowPart;
1491 attr.length.HighPart = size.HighPart;
1492 code = cm_SetAttr(scp, &attr, userp, &req);
1494 else if (infoLevel == 0x102) {
1495 if (*((char *)(p->datap))) {
1496 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1499 fidp->flags |= SMB_FID_DELONCLOSE;
1503 fidp->flags &= ~SMB_FID_DELONCLOSE;
1507 cm_ReleaseUser(userp);
1508 smb_ReleaseFID(fidp);
1509 if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1510 else smb_SendTran2Error(vcp, p, op, code);
1511 smb_FreeTran2Packet(outp);
1516 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1518 return CM_ERROR_BADOP;
1521 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1523 return CM_ERROR_BADOP;
1526 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1528 return CM_ERROR_BADOP;
1531 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1533 return CM_ERROR_BADOP;
1536 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1538 return CM_ERROR_BADOP;
1541 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1542 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1547 cm_scache_t *targetScp; /* target if scp is a symlink */
1552 unsigned short attr;
1553 unsigned long lattr;
1554 smb_dirListPatch_t *patchp;
1555 smb_dirListPatch_t *npatchp;
1557 for(patchp = *dirPatchespp; patchp; patchp =
1558 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1559 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1561 lock_ObtainMutex(&scp->mx);
1562 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1563 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1565 lock_ReleaseMutex(&scp->mx);
1566 cm_ReleaseSCache(scp);
1570 /* now watch for a symlink */
1571 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1572 lock_ReleaseMutex(&scp->mx);
1573 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp,
1576 /* we have a more accurate file to use (the
1577 * target of the symbolic link). Otherwise,
1578 * we'll just use the symlink anyway.
1580 osi_Log2(afsd_logp, "symlink vp %x to vp %x",
1582 cm_ReleaseSCache(scp);
1585 lock_ObtainMutex(&scp->mx);
1588 dptr = patchp->dptr;
1590 if (infoLevel >= 0x101) {
1592 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1594 /* copy to Creation Time */
1595 *((FILETIME *)dptr) = ft;
1598 /* copy to Last Access Time */
1599 *((FILETIME *)dptr) = ft;
1602 /* copy to Last Write Time */
1603 *((FILETIME *)dptr) = ft;
1606 /* copy to Change Time */
1607 *((FILETIME *)dptr) = ft;
1610 /* Use length for both file length and alloc length */
1611 *((LARGE_INTEGER *)dptr) = scp->length;
1613 *((LARGE_INTEGER *)dptr) = scp->length;
1616 /* Copy attributes */
1617 lattr = smb_ExtAttributes(scp);
1618 *((u_long *)dptr) = lattr;
1623 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1625 /* and copy out date */
1626 shortTemp = (dosTime>>16) & 0xffff;
1627 *((u_short *)dptr) = shortTemp;
1630 /* copy out creation time */
1631 shortTemp = dosTime & 0xffff;
1632 *((u_short *)dptr) = shortTemp;
1635 /* and copy out date */
1636 shortTemp = (dosTime>>16) & 0xffff;
1637 *((u_short *)dptr) = shortTemp;
1640 /* copy out access time */
1641 shortTemp = dosTime & 0xffff;
1642 *((u_short *)dptr) = shortTemp;
1645 /* and copy out date */
1646 shortTemp = (dosTime>>16) & 0xffff;
1647 *((u_short *)dptr) = shortTemp;
1650 /* copy out mod time */
1651 shortTemp = dosTime & 0xffff;
1652 *((u_short *)dptr) = shortTemp;
1655 /* copy out file length and alloc length,
1656 * using the same for both
1658 *((u_long *)dptr) = scp->length.LowPart;
1660 *((u_long *)dptr) = scp->length.LowPart;
1663 /* finally copy out attributes as short */
1664 attr = smb_Attributes(scp);
1665 *dptr++ = attr & 0xff;
1666 *dptr++ = (attr >> 8) & 0xff;
1669 lock_ReleaseMutex(&scp->mx);
1670 cm_ReleaseSCache(scp);
1673 /* now free the patches */
1674 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1675 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1679 /* and mark the list as empty */
1680 *dirPatchespp = NULL;
1685 /* do a case-folding search of the star name mask with the name in namep.
1686 * Return 1 if we match, otherwise 0.
1688 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1690 unsigned char tcp1, tcp2; /* Pattern characters */
1691 unsigned char tcn1; /* Name characters */
1692 int sawDot = 0, sawStar = 0;
1693 char *starNamep, *starMaskp;
1694 static char nullCharp[] = {0};
1696 /* make sure we only match 8.3 names, if requested */
1697 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) return 0;
1701 /* Next pattern character */
1704 /* Next name character */
1708 /* 0 - end of pattern */
1714 else if (tcp1 == '.' || tcp1 == '"') {
1724 * first dot in pattern;
1725 * must match dot or end of name
1730 else if (tcn1 == '.') {
1739 else if (tcp1 == '?') {
1740 if (tcn1 == 0 || tcn1 == '.')
1745 else if (tcp1 == '>') {
1746 if (tcn1 != 0 && tcn1 != '.')
1750 else if (tcp1 == '*' || tcp1 == '<') {
1754 else if (tcp2 == '.' || tcp2 == '"') {
1755 while (tcn1 != '.' && tcn1 != 0)
1770 * pattern character after '*' is not null or
1771 * period. If it is '?' or '>', we are not
1772 * going to understand it. If it is '*' or
1773 * '<', we are going to skip over it. None of
1774 * these are likely, I hope.
1776 /* skip over '*' and '<' */
1777 while (tcp2 == '*' || tcp2 == '<')
1780 /* skip over characters that don't match tcp2 */
1781 while (tcn1 != '.' && tcn1 != 0
1782 && cm_foldUpper[tcn1] != cm_foldUpper[tcp2])
1786 if (tcn1 == '.' || tcn1 == 0)
1789 /* Remember where we are */
1799 /* tcp1 is not a wildcard */
1800 if (cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) {
1805 /* if trying to match a star pattern, go back */
1807 maskp = starMaskp - 2;
1808 namep = starNamep + 1;
1818 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1827 smb_dirListPatch_t *dirListPatchesp;
1828 smb_dirListPatch_t *curPatchp;
1831 long orbytes; /* # of bytes in this output record */
1832 long ohbytes; /* # of bytes, except file name */
1833 long onbytes; /* # of bytes in name, incl. term. null */
1834 osi_hyper_t dirLength;
1835 osi_hyper_t bufferOffset;
1836 osi_hyper_t curOffset;
1838 smb_dirSearch_t *dsp;
1842 cm_pageHeader_t *pageHeaderp;
1843 cm_user_t *userp = NULL;
1846 long nextEntryCookie;
1847 int numDirChunks; /* # of 32 byte dir chunks in this entry */
1848 char *op; /* output data ptr */
1849 char *origOp; /* original value of op */
1850 cm_space_t *spacep; /* for pathname buffer */
1851 long maxReturnData; /* max # of return data */
1852 long maxReturnParms; /* max # of return parms */
1853 long bytesInBuffer; /* # data bytes in the output buffer */
1855 char *maskp; /* mask part of path */
1859 smb_tran2Packet_t *outp; /* response packet */
1862 char shortName[13]; /* 8.3 name if needed */
1873 if (p->opcode == 1) {
1874 /* find first; obtain basic parameters from request */
1875 attribute = p->parmsp[0];
1876 maxCount = p->parmsp[1];
1877 infoLevel = p->parmsp[3];
1878 searchFlags = p->parmsp[2];
1879 dsp = smb_NewDirSearch(1);
1880 dsp->attribute = attribute;
1881 pathp = ((char *) p->parmsp) + 12; /* points to path */
1883 maskp = strrchr(pathp, '\\');
1884 if (maskp == NULL) maskp = pathp;
1885 else maskp++; /* skip over backslash */
1886 strcpy(dsp->mask, maskp); /* and save mask */
1887 /* track if this is likely to match a lot of entries */
1888 starPattern = smb_V3IsStarMask(maskp);
1891 osi_assert(p->opcode == 2);
1892 /* find next; obtain basic parameters from request or open dir file */
1893 dsp = smb_FindDirSearch(p->parmsp[0]);
1894 if (!dsp) return CM_ERROR_BADFD;
1895 attribute = dsp->attribute;
1896 maxCount = p->parmsp[1];
1897 infoLevel = p->parmsp[2];
1898 searchFlags = p->parmsp[5];
1900 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
1902 starPattern = 1; /* assume, since required a Find Next */
1906 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
1907 attribute, infoLevel, maxCount, searchFlags);
1909 osi_Log2(afsd_logp, "...T2 search op %d, nextCookie 0x%x",
1910 p->opcode, nextCookie);
1912 if (infoLevel >= 0x101)
1913 searchFlags &= ~4; /* no resume keys */
1915 dirListPatchesp = NULL;
1917 maxReturnData = p->maxReturnData;
1918 if (p->opcode == 1) /* find first */
1919 maxReturnParms = 10; /* bytes */
1921 maxReturnParms = 8; /* bytes */
1923 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
1924 if (maxReturnData > 6000) maxReturnData = 6000;
1925 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
1927 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
1930 osi_Log1(afsd_logp, "T2 receive search dir %s",
1931 osi_LogSaveString(afsd_logp, pathp));
1933 /* bail out if request looks bad */
1934 if (p->opcode == 1 && !pathp) {
1935 return CM_ERROR_BADSMB;
1938 osi_Log2(afsd_logp, "T2 dir search cookie 0x%x, connection %d",
1939 nextCookie, dsp->cookie);
1941 userp = smb_GetTran2User(vcp, p);
1943 /* try to get the vnode for the path name next */
1944 lock_ObtainMutex(&dsp->mx);
1951 spacep = cm_GetSpace();
1952 smb_StripLastComponent(spacep->data, NULL, pathp);
1953 lock_ReleaseMutex(&dsp->mx);
1955 tidPathp = smb_GetTIDPath(vcp, p->tid);
1956 code = cm_NameI(cm_rootSCachep, spacep->data,
1957 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
1958 userp, tidPathp, &req, &scp);
1959 cm_FreeSpace(spacep);
1961 lock_ObtainMutex(&dsp->mx);
1963 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
1965 /* we need one hold for the entry we just stored into,
1966 * and one for our own processing. When we're done
1967 * with this function, we'll drop the one for our own
1968 * processing. We held it once from the namei call,
1969 * and so we do another hold now.
1972 lock_ObtainMutex(&scp->mx);
1973 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
1974 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
1975 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
1976 dsp->flags |= SMB_DIRSEARCH_BULKST;
1978 lock_ReleaseMutex(&scp->mx);
1981 lock_ReleaseMutex(&dsp->mx);
1983 cm_ReleaseUser(userp);
1984 smb_FreeTran2Packet(outp);
1985 smb_DeleteDirSearch(dsp);
1986 smb_ReleaseDirSearch(dsp);
1990 /* get the directory size */
1991 lock_ObtainMutex(&scp->mx);
1992 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1993 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1995 lock_ReleaseMutex(&scp->mx);
1996 cm_ReleaseSCache(scp);
1997 cm_ReleaseUser(userp);
1998 smb_FreeTran2Packet(outp);
1999 smb_DeleteDirSearch(dsp);
2000 smb_ReleaseDirSearch(dsp);
2004 dirLength = scp->length;
2006 bufferOffset.LowPart = bufferOffset.HighPart = 0;
2007 curOffset.HighPart = 0;
2008 curOffset.LowPart = nextCookie;
2009 origOp = outp->datap;
2016 if (searchFlags & 4)
2017 /* skip over resume key */
2020 /* make sure that curOffset.LowPart doesn't point to the first
2021 * 32 bytes in the 2nd through last dir page, and that it doesn't
2022 * point at the first 13 32-byte chunks in the first dir page,
2023 * since those are dir and page headers, and don't contain useful
2026 temp = curOffset.LowPart & (2048-1);
2027 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2028 /* we're in the first page */
2029 if (temp < 13*32) temp = 13*32;
2032 /* we're in a later dir page */
2033 if (temp < 32) temp = 32;
2036 /* make sure the low order 5 bits are zero */
2039 /* now put temp bits back ito curOffset.LowPart */
2040 curOffset.LowPart &= ~(2048-1);
2041 curOffset.LowPart |= temp;
2043 /* check if we've returned all the names that will fit in the
2044 * response packet; we check return count as well as the number
2045 * of bytes requested. We check the # of bytes after we find
2046 * the dir entry, since we'll need to check its size.
2048 if (returnedNames >= maxCount) break;
2050 /* check if we've passed the dir's EOF */
2051 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2056 /* see if we can use the bufferp we have now; compute in which
2057 * page the current offset would be, and check whether that's
2058 * the offset of the buffer we have. If not, get the buffer.
2060 thyper.HighPart = curOffset.HighPart;
2061 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2062 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2065 buf_Release(bufferp);
2068 lock_ReleaseMutex(&scp->mx);
2069 lock_ObtainRead(&scp->bufCreateLock);
2070 code = buf_Get(scp, &thyper, &bufferp);
2071 lock_ReleaseRead(&scp->bufCreateLock);
2073 /* now, if we're doing a star match, do bulk fetching
2074 * of all of the status info for files in the dir.
2077 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2080 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2081 && LargeIntegerGreaterThanOrEqualTo(
2082 thyper, scp->bulkStatProgress)) {
2083 /* Don't bulk stat if risking timeout */
2084 int now = GetCurrentTime();
2085 if (now - req.startTime > 5000) {
2086 scp->bulkStatProgress = thyper;
2087 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2088 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2090 cm_TryBulkStat(scp, &thyper,
2095 lock_ObtainMutex(&scp->mx);
2097 bufferOffset = thyper;
2099 /* now get the data in the cache */
2101 code = cm_SyncOp(scp, bufferp, userp, &req,
2103 CM_SCACHESYNC_NEEDCALLBACK
2104 | CM_SCACHESYNC_READ);
2107 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2109 /* otherwise, load the buffer and try again */
2110 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2115 buf_Release(bufferp);
2119 } /* if (wrong buffer) ... */
2121 /* now we have the buffer containing the entry we're interested
2122 * in; copy it out if it represents a non-deleted entry.
2124 entryInDir = curOffset.LowPart & (2048-1);
2125 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2127 /* page header will help tell us which entries are free. Page
2128 * header can change more often than once per buffer, since
2129 * AFS 3 dir page size may be less than (but not more than)
2130 * a buffer package buffer.
2132 /* only look intra-buffer */
2133 temp = curOffset.LowPart & (buf_bufferSize - 1);
2134 temp &= ~(2048 - 1); /* turn off intra-page bits */
2135 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2137 /* now determine which entry we're looking at in the page.
2138 * If it is free (there's a free bitmap at the start of the
2139 * dir), we should skip these 32 bytes.
2141 slotInPage = (entryInDir & 0x7e0) >> 5;
2142 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2143 & (1 << (slotInPage & 0x7)))) {
2144 /* this entry is free */
2145 numDirChunks = 1; /* only skip this guy */
2149 tp = bufferp->datap + entryInBuffer;
2150 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
2152 /* while we're here, compute the next entry's location, too,
2153 * since we'll need it when writing out the cookie into the dir
2156 * XXXX Probably should do more sanity checking.
2158 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2160 /* compute offset of cookie representing next entry */
2161 nextEntryCookie = curOffset.LowPart
2162 + (CM_DIR_CHUNKSIZE * numDirChunks);
2164 /* Need 8.3 name? */
2166 if (infoLevel == 0x104
2167 && dep->fid.vnode != 0
2168 && !cm_Is8Dot3(dep->name)) {
2169 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2173 if (dep->fid.vnode != 0
2174 && (smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)
2176 && smb_V3MatchMask(shortName, maskp,
2177 CM_FLAG_CASEFOLD)))) {
2179 /* Eliminate entries that don't match requested
2181 if (!(dsp->attribute & 0x10)) /* no directories */
2183 /* We have already done the cm_TryBulkStat above */
2184 fid.cell = scp->fid.cell;
2185 fid.volume = scp->fid.volume;
2186 fid.vnode = ntohl(dep->fid.vnode);
2187 fid.unique = ntohl(dep->fid.unique);
2188 fileType = cm_FindFileType(&fid);
2189 /*osi_Log2(afsd_logp, "smb_ReceiveTran2SearchDir: file %s "
2190 "has filetype %d", dep->name,
2192 if (fileType == CM_SCACHETYPE_DIRECTORY)
2196 /* finally check if this name will fit */
2198 /* standard dir entry stuff */
2199 if (infoLevel < 0x101)
2200 ohbytes = 23; /* pre-NT */
2201 else if (infoLevel == 0x103)
2202 ohbytes = 12; /* NT names only */
2204 ohbytes = 64; /* NT */
2206 if (infoLevel == 0x104)
2207 ohbytes += 26; /* Short name & length */
2209 if (searchFlags & 4) {
2210 ohbytes += 4; /* if resume key required */
2214 && infoLevel != 0x101
2215 && infoLevel != 0x103)
2216 ohbytes += 4; /* EASIZE */
2218 /* add header to name & term. null */
2219 orbytes = onbytes + ohbytes + 1;
2221 /* now, we round up the record to a 4 byte alignment,
2222 * and we make sure that we have enough room here for
2223 * even the aligned version (so we don't have to worry
2224 * about an * overflow when we pad things out below).
2225 * That's the reason for the alignment arithmetic below.
2227 if (infoLevel >= 0x101)
2228 align = (4 - (orbytes & 3)) & 3;
2231 if (orbytes + bytesInBuffer + align > maxReturnData)
2234 /* this is one of the entries to use: it is not deleted
2235 * and it matches the star pattern we're looking for.
2236 * Put out the name, preceded by its length.
2238 /* First zero everything else */
2239 memset(origOp, 0, ohbytes);
2241 if (infoLevel <= 0x101)
2242 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2243 else if (infoLevel == 0x103)
2244 *((u_long *)(op + 8)) = onbytes;
2246 *((u_long *)(op + 60)) = onbytes;
2247 strcpy(origOp+ohbytes, dep->name);
2249 /* Short name if requested and needed */
2250 if (infoLevel == 0x104) {
2251 if (NeedShortName) {
2252 strcpy(op + 70, shortName);
2253 *(op + 68) = shortNameEnd - shortName;
2257 /* now, adjust the # of entries copied */
2260 /* NextEntryOffset and FileIndex */
2261 if (infoLevel >= 101) {
2262 int entryOffset = orbytes + align;
2263 *((u_long *)op) = entryOffset;
2264 *((u_long *)(op+4)) = nextEntryCookie;
2267 /* now we emit the attribute. This is tricky, since
2268 * we need to really stat the file to find out what
2269 * type of entry we've got. Right now, we're copying
2270 * out data from * a buffer, while holding the scp
2271 * locked, so it isn't really convenient to stat
2272 * something now. We'll put in a place holder
2273 * now, and make a second pass before returning this
2274 * to get the real attributes. So, we just skip the
2275 * data for now, and adjust it later. We allocate a
2276 * patch record to make it easy to find this point
2277 * later. The replay will happen at a time when it is
2278 * safe to unlock the directory.
2280 if (infoLevel != 0x103) {
2281 curPatchp = malloc(sizeof(*curPatchp));
2282 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2284 curPatchp->dptr = op;
2285 if (infoLevel >= 0x101)
2286 curPatchp->dptr += 8;
2287 curPatchp->fid.cell = scp->fid.cell;
2288 curPatchp->fid.volume = scp->fid.volume;
2289 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2290 curPatchp->fid.unique = ntohl(dep->fid.unique);
2293 curPatchp->dep = dep;
2296 if (searchFlags & 4)
2297 /* put out resume key */
2298 *((u_long *)origOp) = nextEntryCookie;
2300 /* Adjust byte ptr and count */
2301 origOp += orbytes; /* skip entire record */
2302 bytesInBuffer += orbytes;
2304 /* and pad the record out */
2305 while (--align >= 0) {
2310 } /* if we're including this name */
2313 /* and adjust curOffset to be where the new cookie is */
2314 thyper.HighPart = 0;
2315 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2316 curOffset = LargeIntegerAdd(thyper, curOffset);
2317 } /* while copying data for dir listing */
2319 /* release the mutex */
2320 lock_ReleaseMutex(&scp->mx);
2321 if (bufferp) buf_Release(bufferp);
2323 /* apply and free last set of patches; if not doing a star match, this
2324 * will be empty, but better safe (and freeing everything) than sorry.
2326 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2329 /* now put out the final parameters */
2330 if (returnedNames == 0) eos = 1;
2331 if (p->opcode == 1) {
2333 outp->parmsp[0] = (unsigned short) dsp->cookie;
2334 outp->parmsp[1] = returnedNames;
2335 outp->parmsp[2] = eos;
2336 outp->parmsp[3] = 0; /* nothing wrong with EAS */
2337 outp->parmsp[4] = 0; /* don't need last name to continue
2338 * search, cookie is enough. Normally,
2339 * this is the offset of the file name
2340 * of the last entry returned.
2342 outp->totalParms = 10; /* in bytes */
2346 outp->parmsp[0] = returnedNames;
2347 outp->parmsp[1] = eos;
2348 outp->parmsp[2] = 0; /* EAS error */
2349 outp->parmsp[3] = 0; /* last name, as above */
2350 outp->totalParms = 8; /* in bytes */
2353 /* return # of bytes in the buffer */
2354 outp->totalData = bytesInBuffer;
2356 osi_Log2(afsd_logp, "T2 search dir done, %d names, code %d",
2357 returnedNames, code);
2359 /* Return error code if unsuccessful on first request */
2360 if (code == 0 && p->opcode == 1 && returnedNames == 0)
2361 code = CM_ERROR_NOSUCHFILE;
2363 /* if we're supposed to close the search after this request, or if
2364 * we're supposed to close the search if we're done, and we're done,
2365 * or if something went wrong, close the search.
2367 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2368 if ((searchFlags & 1) || (returnedNames == 0) || ((searchFlags & 2) &&
2370 smb_DeleteDirSearch(dsp);
2372 smb_SendTran2Error(vcp, p, opx, code);
2374 smb_SendTran2Packet(vcp, outp, opx);
2376 smb_FreeTran2Packet(outp);
2377 smb_ReleaseDirSearch(dsp);
2378 cm_ReleaseSCache(scp);
2379 cm_ReleaseUser(userp);
2383 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2386 smb_dirSearch_t *dsp;
2388 dirHandle = smb_GetSMBParm(inp, 0);
2390 osi_Log1(afsd_logp, "SMB3 find close handle %d", dirHandle);
2392 dsp = smb_FindDirSearch(dirHandle);
2395 return CM_ERROR_BADFD;
2397 /* otherwise, we have an FD to destroy */
2398 smb_DeleteDirSearch(dsp);
2399 smb_ReleaseDirSearch(dsp);
2401 /* and return results */
2402 smb_SetSMBDataLength(outp, 0);
2407 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2409 smb_SetSMBDataLength(outp, 0);
2413 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2420 cm_scache_t *dscp; /* dir we're dealing with */
2421 cm_scache_t *scp; /* file we're creating */
2423 int initialModeBits;
2433 int parmSlot; /* which parm we're dealing with */
2441 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
2442 openFun = smb_GetSMBParm(inp, 8); /* open function */
2443 excl = ((openFun & 3) == 0);
2444 trunc = ((openFun & 3) == 2); /* truncate it */
2445 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2446 openAction = 0; /* tracks what we did */
2448 attributes = smb_GetSMBParm(inp, 5);
2449 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2451 /* compute initial mode bits based on read-only flag in attributes */
2452 initialModeBits = 0666;
2453 if (attributes & 1) initialModeBits &= ~0222;
2455 pathp = smb_GetSMBData(inp, NULL);
2457 spacep = inp->spacep;
2458 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2460 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2461 /* special case magic file name for receiving IOCTL requests
2462 * (since IOCTL calls themselves aren't getting through).
2464 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2465 smb_SetupIoctlFid(fidp, spacep);
2467 /* set inp->fid so that later read calls in same msg can find fid */
2468 inp->fid = fidp->fid;
2470 /* copy out remainder of the parms */
2472 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2474 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2475 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
2476 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2477 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
2478 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2479 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2480 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2481 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2483 /* and the final "always present" stuff */
2484 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2485 /* next write out the "unique" ID */
2486 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2487 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2488 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2489 smb_SetSMBDataLength(outp, 0);
2491 /* and clean up fid reference */
2492 smb_ReleaseFID(fidp);
2496 userp = smb_GetUser(vcp, inp);
2499 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2500 code = cm_NameI(cm_rootSCachep, pathp,
2501 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2502 userp, tidPathp, &req, &scp);
2504 code = cm_NameI(cm_rootSCachep, spacep->data,
2505 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2506 userp, tidPathp, &req, &dscp);
2509 cm_ReleaseUser(userp);
2513 /* otherwise, scp points to the parent directory. Do a lookup,
2514 * and truncate the file if we find it, otherwise we create the
2517 if (!lastNamep) lastNamep = pathp;
2519 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2521 if (code && code != CM_ERROR_NOSUCHFILE) {
2522 cm_ReleaseSCache(dscp);
2523 cm_ReleaseUser(userp);
2528 /* if we get here, if code is 0, the file exists and is represented by
2529 * scp. Otherwise, we have to create it. The dir may be represented
2530 * by dscp, or we may have found the file directly. If code is non-zero,
2534 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2536 if (dscp) cm_ReleaseSCache(dscp);
2537 cm_ReleaseSCache(scp);
2538 cm_ReleaseUser(userp);
2543 /* oops, file shouldn't be there */
2544 if (dscp) cm_ReleaseSCache(dscp);
2545 cm_ReleaseSCache(scp);
2546 cm_ReleaseUser(userp);
2547 return CM_ERROR_EXISTS;
2551 setAttr.mask = CM_ATTRMASK_LENGTH;
2552 setAttr.length.LowPart = 0;
2553 setAttr.length.HighPart = 0;
2554 code = cm_SetAttr(scp, &setAttr, userp, &req);
2555 openAction = 3; /* truncated existing file */
2557 else openAction = 1; /* found existing file */
2559 else if (!(openFun & 0x10)) {
2560 /* don't create if not found */
2561 if (dscp) cm_ReleaseSCache(dscp);
2562 cm_ReleaseUser(userp);
2563 return CM_ERROR_NOSUCHFILE;
2566 osi_assert(dscp != NULL);
2567 osi_Log1(afsd_logp, "smb_ReceiveV3OpenX creating file %s",
2568 osi_LogSaveString(afsd_logp, lastNamep));
2569 openAction = 2; /* created file */
2570 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2571 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2572 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2574 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2575 smb_NotifyChange(FILE_ACTION_ADDED,
2576 FILE_NOTIFY_CHANGE_FILE_NAME,
2577 dscp, lastNamep, NULL, TRUE);
2578 if (!excl && code == CM_ERROR_EXISTS) {
2579 /* not an exclusive create, and someone else tried
2580 * creating it already, then we open it anyway. We
2581 * don't bother retrying after this, since if this next
2582 * fails, that means that the file was deleted after we
2583 * started this call.
2585 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2589 setAttr.mask = CM_ATTRMASK_LENGTH;
2590 setAttr.length.LowPart = 0;
2591 setAttr.length.HighPart = 0;
2592 code = cm_SetAttr(scp, &setAttr, userp,
2595 } /* lookup succeeded */
2599 /* we don't need this any longer */
2600 if (dscp) cm_ReleaseSCache(dscp);
2603 /* something went wrong creating or truncating the file */
2604 if (scp) cm_ReleaseSCache(scp);
2605 cm_ReleaseUser(userp);
2609 /* make sure we're about to open a file */
2610 if (scp->fileType != CM_SCACHETYPE_FILE) {
2611 cm_ReleaseSCache(scp);
2612 cm_ReleaseUser(userp);
2613 return CM_ERROR_ISDIR;
2616 /* now all we have to do is open the file itself */
2617 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2620 /* save a pointer to the vnode */
2623 /* compute open mode */
2624 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2625 if (openMode == 1 || openMode == 2)
2626 fidp->flags |= SMB_FID_OPENWRITE;
2628 smb_ReleaseFID(fidp);
2630 cm_Open(scp, 0, userp);
2632 /* set inp->fid so that later read calls in same msg can find fid */
2633 inp->fid = fidp->fid;
2635 /* copy out remainder of the parms */
2637 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2638 lock_ObtainMutex(&scp->mx);
2640 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2641 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2642 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2643 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2644 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2645 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2646 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2647 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2648 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2650 /* and the final "always present" stuff */
2651 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2652 /* next write out the "unique" ID */
2653 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2654 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2655 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2656 lock_ReleaseMutex(&scp->mx);
2657 smb_SetSMBDataLength(outp, 0);
2659 osi_Log1(afsd_logp, "SMB OpenX opening fid %d", fidp->fid);
2661 cm_ReleaseUser(userp);
2662 /* leave scp held since we put it in fidp->scp */
2666 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2673 unsigned char LockType;
2674 unsigned short NumberOfUnlocks, NumberOfLocks;
2675 unsigned long Timeout;
2677 LARGE_INTEGER LOffset, LLength;
2678 smb_waitingLock_t *waitingLock;
2685 fid = smb_GetSMBParm(inp, 2);
2686 fid = smb_ChainFID(fid, inp);
2688 fidp = smb_FindFID(vcp, fid, 0);
2689 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2690 return CM_ERROR_BADFD;
2692 /* set inp->fid so that later read calls in same msg can find fid */
2695 userp = smb_GetUser(vcp, inp);
2699 lock_ObtainMutex(&scp->mx);
2700 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2701 CM_SCACHESYNC_NEEDCALLBACK
2702 | CM_SCACHESYNC_GETSTATUS
2703 | CM_SCACHESYNC_LOCK);
2704 if (code) goto doneSync;
2706 LockType = smb_GetSMBParm(inp, 3) & 0xff;
2707 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2708 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2709 NumberOfLocks = smb_GetSMBParm(inp, 7);
2711 op = smb_GetSMBData(inp, NULL);
2713 for (i=0; i<NumberOfUnlocks; i++) {
2714 if (LockType & 0x10) {
2716 LOffset.HighPart = *((LONG *)(op + 4));
2717 LOffset.LowPart = *((DWORD *)(op + 8));
2718 LLength.HighPart = *((LONG *)(op + 12));
2719 LLength.LowPart = *((DWORD *)(op + 16));
2723 /* Not Large Files */
2724 LOffset.HighPart = 0;
2725 LOffset.LowPart = *((DWORD *)(op + 2));
2726 LLength.HighPart = 0;
2727 LLength.LowPart = *((DWORD *)(op + 6));
2730 if (LargeIntegerNotEqualToZero(LOffset))
2732 /* Do not check length -- length check done in cm_Unlock */
2734 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2735 if (code) goto done;
2738 for (i=0; i<NumberOfLocks; i++) {
2739 if (LockType & 0x10) {
2741 LOffset.HighPart = *((LONG *)(op + 4));
2742 LOffset.LowPart = *((DWORD *)(op + 8));
2743 LLength.HighPart = *((LONG *)(op + 12));
2744 LLength.LowPart = *((DWORD *)(op + 16));
2748 /* Not Large Files */
2749 LOffset.HighPart = 0;
2750 LOffset.LowPart = *((DWORD *)(op + 2));
2751 LLength.HighPart = 0;
2752 LLength.LowPart = *((DWORD *)(op + 6));
2755 if (LargeIntegerNotEqualToZero(LOffset))
2757 if (LargeIntegerLessThan(LOffset, scp->length))
2760 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2761 userp, &req, &lockp);
2762 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2763 /* Put on waiting list */
2764 waitingLock = malloc(sizeof(smb_waitingLock_t));
2765 waitingLock->vcp = vcp;
2766 waitingLock->inp = smb_CopyPacket(inp);
2767 waitingLock->outp = smb_CopyPacket(outp);
2768 waitingLock->timeRemaining = Timeout;
2769 waitingLock->lockp = lockp;
2770 lock_ObtainWrite(&smb_globalLock);
2771 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2773 osi_Wakeup((long) &smb_allWaitingLocks);
2774 lock_ReleaseWrite(&smb_globalLock);
2775 /* don't send reply immediately */
2776 outp->flags |= SMB_PACKETFLAG_NOSEND;
2782 /* release any locks acquired before the failure */
2785 smb_SetSMBDataLength(outp, 0);
2787 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2789 lock_ReleaseMutex(&scp->mx);
2790 cm_ReleaseUser(userp);
2791 smb_ReleaseFID(fidp);
2796 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2808 fid = smb_GetSMBParm(inp, 0);
2809 fid = smb_ChainFID(fid, inp);
2811 fidp = smb_FindFID(vcp, fid, 0);
2812 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2813 return CM_ERROR_BADFD;
2816 userp = smb_GetUser(vcp, inp);
2820 /* otherwise, stat the file */
2821 lock_ObtainMutex(&scp->mx);
2822 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2823 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2824 if (code) goto done;
2826 /* decode times. We need a search time, but the response to this
2827 * call provides the date first, not the time, as returned in the
2828 * searchTime variable. So we take the high-order bits first.
2830 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2831 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
2832 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2833 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
2834 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2835 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
2836 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2838 /* now handle file size and allocation size */
2839 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
2840 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2841 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
2842 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2844 /* file attribute */
2845 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2847 /* and finalize stuff */
2848 smb_SetSMBDataLength(outp, 0);
2852 lock_ReleaseMutex(&scp->mx);
2853 cm_ReleaseUser(userp);
2854 smb_ReleaseFID(fidp);
2858 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2872 fid = smb_GetSMBParm(inp, 0);
2873 fid = smb_ChainFID(fid, inp);
2875 fidp = smb_FindFID(vcp, fid, 0);
2876 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2877 return CM_ERROR_BADFD;
2880 userp = smb_GetUser(vcp, inp);
2884 /* now prepare to call cm_setattr. This message only sets various times,
2885 * and AFS only implements mtime, and we'll set the mtime if that's
2886 * requested. The others we'll ignore.
2888 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
2890 if (searchTime != 0) {
2891 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
2892 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
2893 attrs.clientModTime = unixTime;
2894 code = cm_SetAttr(scp, &attrs, userp, &req);
2898 cm_ReleaseUser(userp);
2899 smb_ReleaseFID(fidp);
2904 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2907 long count, finalCount;
2914 fd = smb_GetSMBParm(inp, 2);
2915 count = smb_GetSMBParm(inp, 5);
2916 offset.HighPart = 0; /* too bad */
2917 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
2919 osi_Log3(afsd_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
2920 fd, offset.LowPart, count);
2922 fd = smb_ChainFID(fd, inp);
2923 fidp = smb_FindFID(vcp, fd, 0);
2925 return CM_ERROR_BADFD;
2927 /* set inp->fid so that later read calls in same msg can find fid */
2930 if (fidp->flags & SMB_FID_IOCTL) {
2931 return smb_IoctlV3Read(fidp, vcp, inp, outp);
2934 userp = smb_GetUser(vcp, inp);
2936 /* 0 and 1 are reserved for request chaining, were setup by our caller,
2937 * and will be further filled in after we return.
2939 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
2940 smb_SetSMBParm(outp, 3, 0); /* resvd */
2941 smb_SetSMBParm(outp, 4, 0); /* resvd */
2942 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
2943 /* fill in #6 when we have all the parameters' space reserved */
2944 smb_SetSMBParm(outp, 7, 0); /* resv'd */
2945 smb_SetSMBParm(outp, 8, 0); /* resv'd */
2946 smb_SetSMBParm(outp, 9, 0); /* resv'd */
2947 smb_SetSMBParm(outp, 10, 0); /* resv'd */
2948 smb_SetSMBParm(outp, 11, 0); /* reserved */
2950 /* get op ptr after putting in the parms, since otherwise we don't
2951 * know where the data really is.
2953 op = smb_GetSMBData(outp, NULL);
2955 /* now fill in offset from start of SMB header to first data byte (to op) */
2956 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
2958 /* set the packet data length the count of the # of bytes */
2959 smb_SetSMBDataLength(outp, count);
2962 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
2964 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
2967 /* fix some things up */
2968 smb_SetSMBParm(outp, 5, finalCount);
2969 smb_SetSMBDataLength(outp, finalCount);
2971 smb_ReleaseFID(fidp);
2973 cm_ReleaseUser(userp);
2978 * Values for createDisp, copied from NTDDK.H
2980 * FILE_SUPERSEDE 0 (???)
2981 * FILE_OPEN 1 (open)
2982 * FILE_CREATE 2 (exclusive)
2983 * FILE_OPEN_IF 3 (non-exclusive)
2984 * FILE_OVERWRITE 4 (open & truncate, but do not create)
2985 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
2988 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2990 char *pathp, *realPathp;
2994 cm_scache_t *dscp; /* parent dir */
2995 cm_scache_t *scp; /* file to create or open */
2998 unsigned short nameLength;
3000 unsigned int requestOpLock;
3001 unsigned int requestBatchOpLock;
3002 unsigned int mustBeDir;
3004 unsigned int desiredAccess;
3005 unsigned int extAttributes;
3006 unsigned int createDisp;
3007 unsigned int createOptions;
3008 int initialModeBits;
3009 unsigned short baseFid;
3010 smb_fid_t *baseFidp;
3012 cm_scache_t *baseDirp;
3013 unsigned short openAction;
3027 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3028 flags = smb_GetSMBOffsetParm(inp, 3, 1)
3029 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3030 requestOpLock = flags & 0x02;
3031 requestBatchOpLock = flags & 0x04;
3032 mustBeDir = flags & 0x08;
3035 * Why all of a sudden 32-bit FID?
3036 * We will reject all bits higher than 16.
3038 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3039 return CM_ERROR_INVAL;
3040 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3041 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3042 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3043 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3044 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3045 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3046 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3047 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3048 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3050 /* mustBeDir is never set; createOptions directory bit seems to be
3053 if (createOptions & 1)
3055 else if (createOptions & 0x40)
3061 * compute initial mode bits based on read-only flag in
3062 * extended attributes
3064 initialModeBits = 0666;
3065 if (extAttributes & 1) initialModeBits &= ~0222;
3067 pathp = smb_GetSMBData(inp, NULL);
3068 /* Sometimes path is not null-terminated, so we make a copy. */
3069 realPathp = malloc(nameLength+1);
3070 memcpy(realPathp, pathp, nameLength);
3071 realPathp[nameLength] = 0;
3073 spacep = inp->spacep;
3074 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3076 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3077 /* special case magic file name for receiving IOCTL requests
3078 * (since IOCTL calls themselves aren't getting through).
3080 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3081 smb_SetupIoctlFid(fidp, spacep);
3083 /* set inp->fid so that later read calls in same msg can find fid */
3084 inp->fid = fidp->fid;
3088 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3089 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3090 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3092 memset(&ft, 0, sizeof(ft));
3093 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3094 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3095 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3096 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3097 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3098 sz.HighPart = 0x7fff; sz.LowPart = 0;
3099 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3100 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3101 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3102 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3103 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
3104 smb_SetSMBDataLength(outp, 0);
3106 /* clean up fid reference */
3107 smb_ReleaseFID(fidp);
3112 userp = smb_GetUser(vcp, inp);
3115 baseDirp = cm_rootSCachep;
3116 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3119 baseFidp = smb_FindFID(vcp, baseFid, 0);
3120 baseDirp = baseFidp->scp;
3124 /* compute open mode */
3126 if (desiredAccess & DELETE)
3127 fidflags |= SMB_FID_OPENDELETE;
3128 if (desiredAccess & AFS_ACCESS_READ)
3129 fidflags |= SMB_FID_OPENREAD;
3130 if (desiredAccess & AFS_ACCESS_WRITE)
3131 fidflags |= SMB_FID_OPENWRITE;
3135 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3136 userp, tidPathp, &req, &scp);
3137 if (code == 0) foundscp = TRUE;
3139 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3140 /* look up parent directory */
3141 code = cm_NameI(baseDirp, spacep->data,
3142 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3143 userp, tidPathp, &req, &dscp);
3145 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3148 cm_ReleaseUser(userp);
3153 if (!lastNamep) lastNamep = realPathp;
3156 if (!smb_IsLegalFilename(lastNamep))
3157 return CM_ERROR_BADNTFILENAME;
3160 code = cm_Lookup(dscp, lastNamep,
3161 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3163 if (code && code != CM_ERROR_NOSUCHFILE) {
3164 cm_ReleaseSCache(dscp);
3165 cm_ReleaseUser(userp);
3172 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3175 /* if we get here, if code is 0, the file exists and is represented by
3176 * scp. Otherwise, we have to create it. The dir may be represented
3177 * by dscp, or we may have found the file directly. If code is non-zero,
3181 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3184 if (dscp) cm_ReleaseSCache(dscp);
3185 cm_ReleaseSCache(scp);
3186 cm_ReleaseUser(userp);
3191 if (createDisp == 2) {
3192 /* oops, file shouldn't be there */
3193 if (dscp) cm_ReleaseSCache(dscp);
3194 cm_ReleaseSCache(scp);
3195 cm_ReleaseUser(userp);
3197 return CM_ERROR_EXISTS;
3201 || createDisp == 5) {
3202 setAttr.mask = CM_ATTRMASK_LENGTH;
3203 setAttr.length.LowPart = 0;
3204 setAttr.length.HighPart = 0;
3205 code = cm_SetAttr(scp, &setAttr, userp, &req);
3206 openAction = 3; /* truncated existing file */
3208 else openAction = 1; /* found existing file */
3210 else if (createDisp == 1 || createDisp == 4) {
3211 /* don't create if not found */
3212 if (dscp) cm_ReleaseSCache(dscp);
3213 cm_ReleaseUser(userp);
3215 return CM_ERROR_NOSUCHFILE;
3217 else if (realDirFlag == 0 || realDirFlag == -1) {
3218 osi_assert(dscp != NULL);
3219 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating file %s",
3220 osi_LogSaveString(afsd_logp, lastNamep));
3221 openAction = 2; /* created file */
3222 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3223 setAttr.clientModTime = time(NULL);
3224 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3226 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3227 smb_NotifyChange(FILE_ACTION_ADDED,
3228 FILE_NOTIFY_CHANGE_FILE_NAME,
3229 dscp, lastNamep, NULL, TRUE);
3230 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3231 /* Not an exclusive create, and someone else tried
3232 * creating it already, then we open it anyway. We
3233 * don't bother retrying after this, since if this next
3234 * fails, that means that the file was deleted after we
3235 * started this call.
3237 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3240 if (createDisp == 5) {
3241 setAttr.mask = CM_ATTRMASK_LENGTH;
3242 setAttr.length.LowPart = 0;
3243 setAttr.length.HighPart = 0;
3244 code = cm_SetAttr(scp, &setAttr, userp,
3247 } /* lookup succeeded */
3251 /* create directory */
3252 osi_assert(dscp != NULL);
3253 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating directory %s",
3254 osi_LogSaveString(afsd_logp, lastNamep));
3255 openAction = 2; /* created directory */
3256 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3257 setAttr.clientModTime = time(NULL);
3258 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3259 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3260 smb_NotifyChange(FILE_ACTION_ADDED,
3261 FILE_NOTIFY_CHANGE_DIR_NAME,
3262 dscp, lastNamep, NULL, TRUE);
3264 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3265 /* Not an exclusive create, and someone else tried
3266 * creating it already, then we open it anyway. We
3267 * don't bother retrying after this, since if this next
3268 * fails, that means that the file was deleted after we
3269 * started this call.
3271 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3277 /* something went wrong creating or truncating the file */
3278 if (scp) cm_ReleaseSCache(scp);
3279 cm_ReleaseUser(userp);
3284 /* make sure we have file vs. dir right */
3285 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3286 cm_ReleaseSCache(scp);
3287 cm_ReleaseUser(userp);
3289 return CM_ERROR_ISDIR;
3291 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3292 cm_ReleaseSCache(scp);
3293 cm_ReleaseUser(userp);
3295 return CM_ERROR_NOTDIR;
3298 /* open the file itself */
3299 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3301 /* save a pointer to the vnode */
3304 fidp->flags = fidflags;
3306 /* save parent dir and pathname for delete or change notification */
3307 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3308 fidp->flags |= SMB_FID_NTOPEN;
3309 fidp->NTopen_dscp = dscp;
3310 cm_HoldSCache(dscp);
3311 fidp->NTopen_pathp = strdup(lastNamep);
3313 fidp->NTopen_wholepathp = realPathp;
3315 /* we don't need this any longer */
3316 if (dscp) cm_ReleaseSCache(dscp);
3317 cm_Open(scp, 0, userp);
3319 /* set inp->fid so that later read calls in same msg can find fid */
3320 inp->fid = fidp->fid;
3324 lock_ObtainMutex(&scp->mx);
3325 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3326 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3327 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3328 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3329 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3330 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3331 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3332 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3333 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3335 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3336 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3337 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3338 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3339 smb_SetSMBParmByte(outp, parmSlot,
3340 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3341 lock_ReleaseMutex(&scp->mx);
3342 smb_SetSMBDataLength(outp, 0);
3344 osi_Log2(afsd_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3345 osi_LogSaveString(afsd_logp, realPathp));
3347 smb_ReleaseFID(fidp);
3349 cm_ReleaseUser(userp);
3351 /* leave scp held since we put it in fidp->scp */
3356 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3357 * Instead, ultimately, would like to use a subroutine for common code.
3359 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3361 char *pathp, *realPathp;
3365 cm_scache_t *dscp; /* parent dir */
3366 cm_scache_t *scp; /* file to create or open */
3369 unsigned long nameLength;
3371 unsigned int requestOpLock;
3372 unsigned int requestBatchOpLock;
3373 unsigned int mustBeDir;
3375 unsigned int desiredAccess;
3376 unsigned int extAttributes;
3377 unsigned int createDisp;
3378 unsigned int createOptions;
3379 int initialModeBits;
3380 unsigned short baseFid;
3381 smb_fid_t *baseFidp;
3383 cm_scache_t *baseDirp;
3384 unsigned short openAction;
3390 int parmOffset, dataOffset;
3401 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3402 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3403 parmp = inp->data + parmOffset;
3404 lparmp = (ULONG *) parmp;
3407 requestOpLock = flags & 0x02;
3408 requestBatchOpLock = flags & 0x04;
3409 mustBeDir = flags & 0x08;
3411 * Why all of a sudden 32-bit FID?
3412 * We will reject all bits higher than 16.
3414 if (lparmp[1] & 0xFFFF0000)
3415 return CM_ERROR_INVAL;
3416 baseFid = (unsigned short)lparmp[1];
3417 desiredAccess = lparmp[2];
3418 extAttributes = lparmp[5];
3419 createDisp = lparmp[7];
3420 createOptions = lparmp[8];
3421 nameLength = lparmp[11];
3423 /* mustBeDir is never set; createOptions directory bit seems to be
3426 if (createOptions & 1)
3428 else if (createOptions & 0x40)
3434 * compute initial mode bits based on read-only flag in
3435 * extended attributes
3437 initialModeBits = 0666;
3438 if (extAttributes & 1) initialModeBits &= ~0222;
3440 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3441 /* Sometimes path is not null-terminated, so we make a copy. */
3442 realPathp = malloc(nameLength+1);
3443 memcpy(realPathp, pathp, nameLength);
3444 realPathp[nameLength] = 0;
3446 spacep = cm_GetSpace();
3447 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3450 * Nothing here to handle SMB_IOCTL_FILENAME.
3451 * Will add it if necessary.
3454 userp = smb_GetUser(vcp, inp);
3457 baseDirp = cm_rootSCachep;
3458 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3461 baseFidp = smb_FindFID(vcp, baseFid, 0);
3462 baseDirp = baseFidp->scp;
3466 /* compute open mode */
3468 if (desiredAccess & DELETE)
3469 fidflags |= SMB_FID_OPENDELETE;
3470 if (desiredAccess & AFS_ACCESS_READ)
3471 fidflags |= SMB_FID_OPENREAD;
3472 if (desiredAccess & AFS_ACCESS_WRITE)
3473 fidflags |= SMB_FID_OPENWRITE;
3477 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3478 userp, tidPathp, &req, &scp);
3479 if (code == 0) foundscp = TRUE;
3481 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3482 /* look up parent directory */
3483 code = cm_NameI(baseDirp, spacep->data,
3484 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3485 userp, tidPathp, &req, &dscp);
3486 cm_FreeSpace(spacep);
3488 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3491 cm_ReleaseUser(userp);
3496 if (!lastNamep) lastNamep = realPathp;
3499 if (!smb_IsLegalFilename(lastNamep))
3500 return CM_ERROR_BADNTFILENAME;
3503 code = cm_Lookup(dscp, lastNamep,
3504 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3506 if (code && code != CM_ERROR_NOSUCHFILE) {
3507 cm_ReleaseSCache(dscp);
3508 cm_ReleaseUser(userp);
3515 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3516 cm_FreeSpace(spacep);
3519 /* if we get here, if code is 0, the file exists and is represented by
3520 * scp. Otherwise, we have to create it. The dir may be represented
3521 * by dscp, or we may have found the file directly. If code is non-zero,
3525 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3528 if (dscp) cm_ReleaseSCache(dscp);
3529 cm_ReleaseSCache(scp);
3530 cm_ReleaseUser(userp);
3535 if (createDisp == 2) {
3536 /* oops, file shouldn't be there */
3537 if (dscp) cm_ReleaseSCache(dscp);
3538 cm_ReleaseSCache(scp);
3539 cm_ReleaseUser(userp);
3541 return CM_ERROR_EXISTS;
3545 || createDisp == 5) {
3546 setAttr.mask = CM_ATTRMASK_LENGTH;
3547 setAttr.length.LowPart = 0;
3548 setAttr.length.HighPart = 0;
3549 code = cm_SetAttr(scp, &setAttr, userp, &req);
3550 openAction = 3; /* truncated existing file */
3552 else openAction = 1; /* found existing file */
3554 else if (createDisp == 1 || createDisp == 4) {
3555 /* don't create if not found */
3556 if (dscp) cm_ReleaseSCache(dscp);
3557 cm_ReleaseUser(userp);
3559 return CM_ERROR_NOSUCHFILE;
3561 else if (realDirFlag == 0 || realDirFlag == -1) {
3562 osi_assert(dscp != NULL);
3563 osi_Log1(afsd_logp, "smb_ReceiveNTTranCreate creating file %s",
3564 osi_LogSaveString(afsd_logp, lastNamep));
3565 openAction = 2; /* created file */
3566 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3567 setAttr.clientModTime = time(NULL);
3568 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3570 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3571 smb_NotifyChange(FILE_ACTION_ADDED,
3572 FILE_NOTIFY_CHANGE_FILE_NAME,
3573 dscp, lastNamep, NULL, TRUE);
3574 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3575 /* Not an exclusive create, and someone else tried
3576 * creating it already, then we open it anyway. We
3577 * don't bother retrying after this, since if this next
3578 * fails, that means that the file was deleted after we
3579 * started this call.
3581 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3584 if (createDisp == 5) {
3585 setAttr.mask = CM_ATTRMASK_LENGTH;
3586 setAttr.length.LowPart = 0;
3587 setAttr.length.HighPart = 0;
3588 code = cm_SetAttr(scp, &setAttr, userp,
3591 } /* lookup succeeded */
3595 /* create directory */
3596 osi_assert(dscp != NULL);
3598 "smb_ReceiveNTTranCreate creating directory %s",
3599 osi_LogSaveString(afsd_logp, lastNamep));
3600 openAction = 2; /* created directory */
3601 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3602 setAttr.clientModTime = time(NULL);
3603 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3604 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3605 smb_NotifyChange(FILE_ACTION_ADDED,
3606 FILE_NOTIFY_CHANGE_DIR_NAME,
3607 dscp, lastNamep, NULL, TRUE);
3609 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3610 /* Not an exclusive create, and someone else tried
3611 * creating it already, then we open it anyway. We
3612 * don't bother retrying after this, since if this next
3613 * fails, that means that the file was deleted after we
3614 * started this call.
3616 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3622 /* something went wrong creating or truncating the file */
3623 if (scp) cm_ReleaseSCache(scp);
3624 cm_ReleaseUser(userp);
3629 /* make sure we have file vs. dir right */
3630 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3631 cm_ReleaseSCache(scp);
3632 cm_ReleaseUser(userp);
3634 return CM_ERROR_ISDIR;
3636 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3637 cm_ReleaseSCache(scp);
3638 cm_ReleaseUser(userp);
3640 return CM_ERROR_NOTDIR;
3643 /* open the file itself */
3644 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3647 /* save a pointer to the vnode */
3650 fidp->flags = fidflags;
3652 /* save parent dir and pathname for deletion or change notification */
3653 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3654 fidp->flags |= SMB_FID_NTOPEN;
3655 fidp->NTopen_dscp = dscp;
3656 cm_HoldSCache(dscp);
3657 fidp->NTopen_pathp = strdup(lastNamep);
3659 fidp->NTopen_wholepathp = realPathp;
3661 /* we don't need this any longer */
3662 if (dscp) cm_ReleaseSCache(dscp);
3664 cm_Open(scp, 0, userp);
3666 /* set inp->fid so that later read calls in same msg can find fid */
3667 inp->fid = fidp->fid;
3670 parmOffset = 8*4 + 39;
3671 parmOffset += 1; /* pad to 4 */
3672 dataOffset = parmOffset + 70;
3676 /* Total Parameter Count */
3677 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;