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)
2369 || code != 0) smb_DeleteDirSearch(dsp);
2371 smb_SendTran2Error(vcp, p, opx, code);
2373 smb_SendTran2Packet(vcp, outp, opx);
2375 smb_FreeTran2Packet(outp);
2376 smb_ReleaseDirSearch(dsp);
2377 cm_ReleaseSCache(scp);
2378 cm_ReleaseUser(userp);
2382 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2385 smb_dirSearch_t *dsp;
2387 dirHandle = smb_GetSMBParm(inp, 0);
2389 osi_Log1(afsd_logp, "SMB3 find close handle %d", dirHandle);
2391 dsp = smb_FindDirSearch(dirHandle);
2394 return CM_ERROR_BADFD;
2396 /* otherwise, we have an FD to destroy */
2397 smb_DeleteDirSearch(dsp);
2398 smb_ReleaseDirSearch(dsp);
2400 /* and return results */
2401 smb_SetSMBDataLength(outp, 0);
2406 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2408 smb_SetSMBDataLength(outp, 0);
2412 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2419 cm_scache_t *dscp; /* dir we're dealing with */
2420 cm_scache_t *scp; /* file we're creating */
2422 int initialModeBits;
2432 int parmSlot; /* which parm we're dealing with */
2440 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
2441 openFun = smb_GetSMBParm(inp, 8); /* open function */
2442 excl = ((openFun & 3) == 0);
2443 trunc = ((openFun & 3) == 2); /* truncate it */
2444 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2445 openAction = 0; /* tracks what we did */
2447 attributes = smb_GetSMBParm(inp, 5);
2448 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2450 /* compute initial mode bits based on read-only flag in attributes */
2451 initialModeBits = 0666;
2452 if (attributes & 1) initialModeBits &= ~0222;
2454 pathp = smb_GetSMBData(inp, NULL);
2456 spacep = inp->spacep;
2457 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2459 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2460 /* special case magic file name for receiving IOCTL requests
2461 * (since IOCTL calls themselves aren't getting through).
2463 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2464 smb_SetupIoctlFid(fidp, spacep);
2466 /* set inp->fid so that later read calls in same msg can find fid */
2467 inp->fid = fidp->fid;
2469 /* copy out remainder of the parms */
2471 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2473 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2474 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
2475 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2476 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
2477 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2478 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2479 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2480 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2482 /* and the final "always present" stuff */
2483 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2484 /* next write out the "unique" ID */
2485 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2486 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2487 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2488 smb_SetSMBDataLength(outp, 0);
2490 /* and clean up fid reference */
2491 smb_ReleaseFID(fidp);
2495 userp = smb_GetUser(vcp, inp);
2498 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2499 code = cm_NameI(cm_rootSCachep, pathp,
2500 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2501 userp, tidPathp, &req, &scp);
2503 code = cm_NameI(cm_rootSCachep, spacep->data,
2504 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2505 userp, tidPathp, &req, &dscp);
2508 cm_ReleaseUser(userp);
2512 /* otherwise, scp points to the parent directory. Do a lookup,
2513 * and truncate the file if we find it, otherwise we create the
2516 if (!lastNamep) lastNamep = pathp;
2518 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2520 if (code && code != CM_ERROR_NOSUCHFILE) {
2521 cm_ReleaseSCache(dscp);
2522 cm_ReleaseUser(userp);
2527 /* if we get here, if code is 0, the file exists and is represented by
2528 * scp. Otherwise, we have to create it. The dir may be represented
2529 * by dscp, or we may have found the file directly. If code is non-zero,
2533 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2535 if (dscp) cm_ReleaseSCache(dscp);
2536 cm_ReleaseSCache(scp);
2537 cm_ReleaseUser(userp);
2542 /* oops, file shouldn't be there */
2543 if (dscp) cm_ReleaseSCache(dscp);
2544 cm_ReleaseSCache(scp);
2545 cm_ReleaseUser(userp);
2546 return CM_ERROR_EXISTS;
2550 setAttr.mask = CM_ATTRMASK_LENGTH;
2551 setAttr.length.LowPart = 0;
2552 setAttr.length.HighPart = 0;
2553 code = cm_SetAttr(scp, &setAttr, userp, &req);
2554 openAction = 3; /* truncated existing file */
2556 else openAction = 1; /* found existing file */
2558 else if (!(openFun & 0x10)) {
2559 /* don't create if not found */
2560 if (dscp) cm_ReleaseSCache(dscp);
2561 cm_ReleaseUser(userp);
2562 return CM_ERROR_NOSUCHFILE;
2565 osi_assert(dscp != NULL);
2566 osi_Log1(afsd_logp, "smb_ReceiveV3OpenX creating file %s",
2567 osi_LogSaveString(afsd_logp, lastNamep));
2568 openAction = 2; /* created file */
2569 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2570 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2571 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2573 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2574 smb_NotifyChange(FILE_ACTION_ADDED,
2575 FILE_NOTIFY_CHANGE_FILE_NAME,
2576 dscp, lastNamep, NULL, TRUE);
2577 if (!excl && code == CM_ERROR_EXISTS) {
2578 /* not an exclusive create, and someone else tried
2579 * creating it already, then we open it anyway. We
2580 * don't bother retrying after this, since if this next
2581 * fails, that means that the file was deleted after we
2582 * started this call.
2584 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2588 setAttr.mask = CM_ATTRMASK_LENGTH;
2589 setAttr.length.LowPart = 0;
2590 setAttr.length.HighPart = 0;
2591 code = cm_SetAttr(scp, &setAttr, userp,
2594 } /* lookup succeeded */
2598 /* we don't need this any longer */
2599 if (dscp) cm_ReleaseSCache(dscp);
2602 /* something went wrong creating or truncating the file */
2603 if (scp) cm_ReleaseSCache(scp);
2604 cm_ReleaseUser(userp);
2608 /* make sure we're about to open a file */
2609 if (scp->fileType != CM_SCACHETYPE_FILE) {
2610 cm_ReleaseSCache(scp);
2611 cm_ReleaseUser(userp);
2612 return CM_ERROR_ISDIR;
2615 /* now all we have to do is open the file itself */
2616 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2619 /* save a pointer to the vnode */
2622 /* compute open mode */
2623 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2624 if (openMode == 1 || openMode == 2)
2625 fidp->flags |= SMB_FID_OPENWRITE;
2627 smb_ReleaseFID(fidp);
2629 cm_Open(scp, 0, userp);
2631 /* set inp->fid so that later read calls in same msg can find fid */
2632 inp->fid = fidp->fid;
2634 /* copy out remainder of the parms */
2636 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2637 lock_ObtainMutex(&scp->mx);
2639 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2640 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2641 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2642 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2643 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2644 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2645 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2646 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2647 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2649 /* and the final "always present" stuff */
2650 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2651 /* next write out the "unique" ID */
2652 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2653 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2654 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2655 lock_ReleaseMutex(&scp->mx);
2656 smb_SetSMBDataLength(outp, 0);
2658 osi_Log1(afsd_logp, "SMB OpenX opening fid %d", fidp->fid);
2660 cm_ReleaseUser(userp);
2661 /* leave scp held since we put it in fidp->scp */
2665 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2672 unsigned char LockType;
2673 unsigned short NumberOfUnlocks, NumberOfLocks;
2674 unsigned long Timeout;
2676 LARGE_INTEGER LOffset, LLength;
2677 smb_waitingLock_t *waitingLock;
2684 fid = smb_GetSMBParm(inp, 2);
2685 fid = smb_ChainFID(fid, inp);
2687 fidp = smb_FindFID(vcp, fid, 0);
2688 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2689 return CM_ERROR_BADFD;
2691 /* set inp->fid so that later read calls in same msg can find fid */
2694 userp = smb_GetUser(vcp, inp);
2698 lock_ObtainMutex(&scp->mx);
2699 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2700 CM_SCACHESYNC_NEEDCALLBACK
2701 | CM_SCACHESYNC_GETSTATUS
2702 | CM_SCACHESYNC_LOCK);
2703 if (code) goto doneSync;
2705 LockType = smb_GetSMBParm(inp, 3) & 0xff;
2706 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2707 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2708 NumberOfLocks = smb_GetSMBParm(inp, 7);
2710 op = smb_GetSMBData(inp, NULL);
2712 for (i=0; i<NumberOfUnlocks; i++) {
2713 if (LockType & 0x10) {
2715 LOffset.HighPart = *((LONG *)(op + 4));
2716 LOffset.LowPart = *((DWORD *)(op + 8));
2717 LLength.HighPart = *((LONG *)(op + 12));
2718 LLength.LowPart = *((DWORD *)(op + 16));
2722 /* Not Large Files */
2723 LOffset.HighPart = 0;
2724 LOffset.LowPart = *((DWORD *)(op + 2));
2725 LLength.HighPart = 0;
2726 LLength.LowPart = *((DWORD *)(op + 6));
2729 if (LargeIntegerNotEqualToZero(LOffset))
2731 /* Do not check length -- length check done in cm_Unlock */
2733 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2734 if (code) goto done;
2737 for (i=0; i<NumberOfLocks; i++) {
2738 if (LockType & 0x10) {
2740 LOffset.HighPart = *((LONG *)(op + 4));
2741 LOffset.LowPart = *((DWORD *)(op + 8));
2742 LLength.HighPart = *((LONG *)(op + 12));
2743 LLength.LowPart = *((DWORD *)(op + 16));
2747 /* Not Large Files */
2748 LOffset.HighPart = 0;
2749 LOffset.LowPart = *((DWORD *)(op + 2));
2750 LLength.HighPart = 0;
2751 LLength.LowPart = *((DWORD *)(op + 6));
2754 if (LargeIntegerNotEqualToZero(LOffset))
2756 if (LargeIntegerLessThan(LOffset, scp->length))
2759 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2760 userp, &req, &lockp);
2761 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2762 /* Put on waiting list */
2763 waitingLock = malloc(sizeof(smb_waitingLock_t));
2764 waitingLock->vcp = vcp;
2765 waitingLock->inp = smb_CopyPacket(inp);
2766 waitingLock->outp = smb_CopyPacket(outp);
2767 waitingLock->timeRemaining = Timeout;
2768 waitingLock->lockp = lockp;
2769 lock_ObtainWrite(&smb_globalLock);
2770 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2772 osi_Wakeup((long) &smb_allWaitingLocks);
2773 lock_ReleaseWrite(&smb_globalLock);
2774 /* don't send reply immediately */
2775 outp->flags |= SMB_PACKETFLAG_NOSEND;
2781 /* release any locks acquired before the failure */
2784 smb_SetSMBDataLength(outp, 0);
2786 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2788 lock_ReleaseMutex(&scp->mx);
2789 cm_ReleaseUser(userp);
2790 smb_ReleaseFID(fidp);
2795 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2807 fid = smb_GetSMBParm(inp, 0);
2808 fid = smb_ChainFID(fid, inp);
2810 fidp = smb_FindFID(vcp, fid, 0);
2811 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2812 return CM_ERROR_BADFD;
2815 userp = smb_GetUser(vcp, inp);
2819 /* otherwise, stat the file */
2820 lock_ObtainMutex(&scp->mx);
2821 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2822 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2823 if (code) goto done;
2825 /* decode times. We need a search time, but the response to this
2826 * call provides the date first, not the time, as returned in the
2827 * searchTime variable. So we take the high-order bits first.
2829 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2830 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
2831 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2832 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
2833 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2834 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
2835 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2837 /* now handle file size and allocation size */
2838 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
2839 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2840 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
2841 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2843 /* file attribute */
2844 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2846 /* and finalize stuff */
2847 smb_SetSMBDataLength(outp, 0);
2851 lock_ReleaseMutex(&scp->mx);
2852 cm_ReleaseUser(userp);
2853 smb_ReleaseFID(fidp);
2857 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2871 fid = smb_GetSMBParm(inp, 0);
2872 fid = smb_ChainFID(fid, inp);
2874 fidp = smb_FindFID(vcp, fid, 0);
2875 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2876 return CM_ERROR_BADFD;
2879 userp = smb_GetUser(vcp, inp);
2883 /* now prepare to call cm_setattr. This message only sets various times,
2884 * and AFS only implements mtime, and we'll set the mtime if that's
2885 * requested. The others we'll ignore.
2887 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
2889 if (searchTime != 0) {
2890 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
2891 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
2892 attrs.clientModTime = unixTime;
2893 code = cm_SetAttr(scp, &attrs, userp, &req);
2897 cm_ReleaseUser(userp);
2898 smb_ReleaseFID(fidp);
2903 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2906 long count, finalCount;
2913 fd = smb_GetSMBParm(inp, 2);
2914 count = smb_GetSMBParm(inp, 5);
2915 offset.HighPart = 0; /* too bad */
2916 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
2918 osi_Log3(afsd_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
2919 fd, offset.LowPart, count);
2921 fd = smb_ChainFID(fd, inp);
2922 fidp = smb_FindFID(vcp, fd, 0);
2924 return CM_ERROR_BADFD;
2926 /* set inp->fid so that later read calls in same msg can find fid */
2929 if (fidp->flags & SMB_FID_IOCTL) {
2930 return smb_IoctlV3Read(fidp, vcp, inp, outp);
2933 userp = smb_GetUser(vcp, inp);
2935 /* 0 and 1 are reserved for request chaining, were setup by our caller,
2936 * and will be further filled in after we return.
2938 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
2939 smb_SetSMBParm(outp, 3, 0); /* resvd */
2940 smb_SetSMBParm(outp, 4, 0); /* resvd */
2941 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
2942 /* fill in #6 when we have all the parameters' space reserved */
2943 smb_SetSMBParm(outp, 7, 0); /* resv'd */
2944 smb_SetSMBParm(outp, 8, 0); /* resv'd */
2945 smb_SetSMBParm(outp, 9, 0); /* resv'd */
2946 smb_SetSMBParm(outp, 10, 0); /* resv'd */
2947 smb_SetSMBParm(outp, 11, 0); /* reserved */
2949 /* get op ptr after putting in the parms, since otherwise we don't
2950 * know where the data really is.
2952 op = smb_GetSMBData(outp, NULL);
2954 /* now fill in offset from start of SMB header to first data byte (to op) */
2955 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
2957 /* set the packet data length the count of the # of bytes */
2958 smb_SetSMBDataLength(outp, count);
2961 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
2963 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
2966 /* fix some things up */
2967 smb_SetSMBParm(outp, 5, finalCount);
2968 smb_SetSMBDataLength(outp, finalCount);
2970 smb_ReleaseFID(fidp);
2972 cm_ReleaseUser(userp);
2977 * Values for createDisp, copied from NTDDK.H
2979 * FILE_SUPERSEDE 0 (???)
2980 * FILE_OPEN 1 (open)
2981 * FILE_CREATE 2 (exclusive)
2982 * FILE_OPEN_IF 3 (non-exclusive)
2983 * FILE_OVERWRITE 4 (open & truncate, but do not create)
2984 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
2987 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2989 char *pathp, *realPathp;
2993 cm_scache_t *dscp; /* parent dir */
2994 cm_scache_t *scp; /* file to create or open */
2997 unsigned short nameLength;
2999 unsigned int requestOpLock;
3000 unsigned int requestBatchOpLock;
3001 unsigned int mustBeDir;
3003 unsigned int desiredAccess;
3004 unsigned int extAttributes;
3005 unsigned int createDisp;
3006 unsigned int createOptions;
3007 int initialModeBits;
3008 unsigned short baseFid;
3009 smb_fid_t *baseFidp;
3011 cm_scache_t *baseDirp;
3012 unsigned short openAction;
3026 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3027 flags = smb_GetSMBOffsetParm(inp, 3, 1)
3028 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3029 requestOpLock = flags & 0x02;
3030 requestBatchOpLock = flags & 0x04;
3031 mustBeDir = flags & 0x08;
3034 * Why all of a sudden 32-bit FID?
3035 * We will reject all bits higher than 16.
3037 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3038 return CM_ERROR_INVAL;
3039 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3040 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3041 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3042 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3043 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3044 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3045 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3046 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3047 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3049 /* mustBeDir is never set; createOptions directory bit seems to be
3052 if (createOptions & 1)
3054 else if (createOptions & 0x40)
3060 * compute initial mode bits based on read-only flag in
3061 * extended attributes
3063 initialModeBits = 0666;
3064 if (extAttributes & 1) initialModeBits &= ~0222;
3066 pathp = smb_GetSMBData(inp, NULL);
3067 /* Sometimes path is not null-terminated, so we make a copy. */
3068 realPathp = malloc(nameLength+1);
3069 memcpy(realPathp, pathp, nameLength);
3070 realPathp[nameLength] = 0;
3072 spacep = inp->spacep;
3073 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3075 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3076 /* special case magic file name for receiving IOCTL requests
3077 * (since IOCTL calls themselves aren't getting through).
3079 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3080 smb_SetupIoctlFid(fidp, spacep);
3082 /* set inp->fid so that later read calls in same msg can find fid */
3083 inp->fid = fidp->fid;
3087 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3088 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3089 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3091 memset(&ft, 0, sizeof(ft));
3092 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
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_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3097 sz.HighPart = 0x7fff; sz.LowPart = 0;
3098 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3099 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3100 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3101 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3102 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
3103 smb_SetSMBDataLength(outp, 0);
3105 /* clean up fid reference */
3106 smb_ReleaseFID(fidp);
3111 userp = smb_GetUser(vcp, inp);
3114 baseDirp = cm_rootSCachep;
3115 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3118 baseFidp = smb_FindFID(vcp, baseFid, 0);
3119 baseDirp = baseFidp->scp;
3123 /* compute open mode */
3125 if (desiredAccess & DELETE)
3126 fidflags |= SMB_FID_OPENDELETE;
3127 if (desiredAccess & AFS_ACCESS_READ)
3128 fidflags |= SMB_FID_OPENREAD;
3129 if (desiredAccess & AFS_ACCESS_WRITE)
3130 fidflags |= SMB_FID_OPENWRITE;
3134 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3135 userp, tidPathp, &req, &scp);
3136 if (code == 0) foundscp = TRUE;
3138 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3139 /* look up parent directory */
3140 code = cm_NameI(baseDirp, spacep->data,
3141 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3142 userp, tidPathp, &req, &dscp);
3144 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3147 cm_ReleaseUser(userp);
3152 if (!lastNamep) lastNamep = realPathp;
3155 if (!smb_IsLegalFilename(lastNamep))
3156 return CM_ERROR_BADNTFILENAME;
3159 code = cm_Lookup(dscp, lastNamep,
3160 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3162 if (code && code != CM_ERROR_NOSUCHFILE) {
3163 cm_ReleaseSCache(dscp);
3164 cm_ReleaseUser(userp);
3171 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3174 /* if we get here, if code is 0, the file exists and is represented by
3175 * scp. Otherwise, we have to create it. The dir may be represented
3176 * by dscp, or we may have found the file directly. If code is non-zero,
3180 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3183 if (dscp) cm_ReleaseSCache(dscp);
3184 cm_ReleaseSCache(scp);
3185 cm_ReleaseUser(userp);
3190 if (createDisp == 2) {
3191 /* oops, file shouldn't be there */
3192 if (dscp) cm_ReleaseSCache(dscp);
3193 cm_ReleaseSCache(scp);