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 if (strlen(usern)==0) {
143 /*return CM_ERROR_NOACCESS;*/
144 newUid = 0; /* always assign uid 0 for blank username */
145 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
148 HANDLE h; char *ptbuf[1],buf[132];
149 h = RegisterEventSource(NULL, "AFS Service - smb_ReceiveV3SessionSetupX");
150 sprintf(buf, "VCP[%x] lsn[%d] anonymous, uid[%d]",vcp,vcp->lsn,uidp->userID);
152 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
153 DeregisterEventSource(h);
156 smb_ReleaseUID(uidp);
160 /* On Windows 2000, this function appears to be called more often than
161 it is expected to be called. This resulted in multiple smb_user_t
162 records existing all for the same user session which results in all
163 of the users tokens disappearing.
165 To avoid this problem, we look for an existing smb_user_t record
166 based on the users name, and use that one if we find it.
169 uidp = smb_FindUserByNameThisSession(vcp, usern);
170 if (uidp) { /* already there, so don't create a new one */
173 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
176 HANDLE h; char *ptbuf[1],buf[132];
177 h = RegisterEventSource(NULL, "AFS Service - smb_ReceiveV3SessionSetupX");
178 sprintf(buf,"FindUserByName:VCP[%x],Lana[%d],lsn[%d],userid[%d],name[%s]",vcp,vcp->lana,vcp->lsn,newUid,usern);
180 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
181 DeregisterEventSource(h);
184 smb_ReleaseUID(uidp);
187 /* do a global search for the username/machine name pair */
188 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
190 /* Create a new UID and cm_user_t structure */
193 userp = cm_NewUser();
194 lock_ObtainMutex(&vcp->mx);
195 newUid = vcp->uidCounter++;
196 lock_ReleaseMutex(&vcp->mx);
198 /* Create a new smb_user_t structure and connect them up */
199 lock_ObtainMutex(&unp->mx);
201 lock_ReleaseMutex(&unp->mx);
203 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
204 lock_ObtainMutex(&uidp->mx);
208 HANDLE h; char *ptbuf[1],buf[132];
209 h = RegisterEventSource(NULL, "AFS Service - smb_ReceiveV3SessionSetupX");
210 sprintf(buf,"NewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],name[%s]",vcp,vcp->lana,vcp->lsn,newUid,usern);
212 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
213 DeregisterEventSource(h);
216 lock_ReleaseMutex(&uidp->mx);
217 smb_ReleaseUID(uidp);
221 /* Return UID to the client */
222 ((smb_t *)outp)->uid = newUid;
223 /* Also to the next chained message */
224 ((smb_t *)inp)->uid = newUid;
226 osi_Log3(afsd_logp, "SMB3 session setup name %s creating ID %d%s",
227 osi_LogSaveString(afsd_logp, usern), newUid, osi_LogSaveString(afsd_logp, s1));
228 smb_SetSMBParm(outp, 2, 0);
229 smb_SetSMBDataLength(outp, 0);
233 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
237 /* don't get tokens from this VC */
238 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
240 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
242 /* find the tree and free it */
243 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
245 char *s1 = NULL, *s2 = NULL;
247 if (s2 == NULL) s2 = " ";
248 if (s1 == NULL) {s1 = s2; s2 = " ";}
250 osi_Log4(afsd_logp, "SMB3 user logoffX uid %d name %s%s%s",
252 osi_LogSaveString(afsd_logp,
253 (uidp->unp) ? uidp->unp->name: " "), s1, s2);
255 lock_ObtainMutex(&uidp->mx);
256 uidp->flags |= SMB_USERFLAG_DELETE;
258 * it doesn't get deleted right away
259 * because the vcp points to it
261 lock_ReleaseMutex(&uidp->mx);
264 osi_Log0(afsd_logp, "SMB3 user logoffX");
266 smb_SetSMBDataLength(outp, 0);
270 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
273 unsigned short newTid;
283 osi_Log0(afsd_logp, "SMB3 receive tree connect");
285 /* parse input parameters */
286 tp = smb_GetSMBData(inp, NULL);
287 passwordp = smb_ParseString(tp, &tp);
288 pathp = smb_ParseString(tp, &tp);
289 servicep = smb_ParseString(tp, &tp);
291 tp = strrchr(pathp, '\\');
293 return CM_ERROR_BADSMB;
295 strcpy(shareName, tp+1);
297 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0)
298 return CM_ERROR_NOIPC;
300 userp = smb_GetUser(vcp, inp);
302 lock_ObtainMutex(&vcp->mx);
303 newTid = vcp->tidCounter++;
304 lock_ReleaseMutex(&vcp->mx);
306 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
307 shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
309 smb_ReleaseTID(tidp);
310 return CM_ERROR_BADSHARENAME;
312 lock_ObtainMutex(&tidp->mx);
314 tidp->pathname = sharePath;
315 lock_ReleaseMutex(&tidp->mx);
316 smb_ReleaseTID(tidp);
318 if (vcp->flags & SMB_VCFLAG_USENT)
319 smb_SetSMBParm(outp, 2, 0); /* OptionalSupport bits */
321 ((smb_t *)outp)->tid = newTid;
322 ((smb_t *)inp)->tid = newTid;
323 tp = smb_GetSMBData(outp, NULL);
327 smb_SetSMBDataLength(outp, 3);
329 osi_Log1(afsd_logp, "SMB3 tree connect created ID %d", newTid);
333 /* must be called with global tran lock held */
334 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
336 smb_tran2Packet_t *tp;
339 smbp = (smb_t *) inp->data;
340 for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
341 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
347 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
348 int totalParms, int totalData)
350 smb_tran2Packet_t *tp;
353 smbp = (smb_t *) inp->data;
354 tp = malloc(sizeof(*tp));
355 memset(tp, 0, sizeof(*tp));
358 tp->curData = tp->curParms = 0;
359 tp->totalData = totalData;
360 tp->totalParms = totalParms;
365 tp->res[0] = smbp->res[0];
366 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
367 tp->opcode = smb_GetSMBParm(inp, 14);
369 tp->parmsp = malloc(totalParms);
371 tp->datap = malloc(totalData);
372 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
376 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
377 smb_tran2Packet_t *inp, smb_packet_t *outp,
378 int totalParms, int totalData)
380 smb_tran2Packet_t *tp;
381 unsigned short parmOffset;
382 unsigned short dataOffset;
383 unsigned short dataAlign;
385 tp = malloc(sizeof(*tp));
386 memset(tp, 0, sizeof(*tp));
388 tp->curData = tp->curParms = 0;
389 tp->totalData = totalData;
390 tp->totalParms = totalParms;
391 tp->oldTotalParms = totalParms;
396 tp->res[0] = inp->res[0];
397 tp->opcode = inp->opcode;
400 * We calculate where the parameters and data will start.
401 * This calculation must parallel the calculation in
402 * smb_SendTran2Packet.
405 parmOffset = 10*2 + 35;
406 parmOffset++; /* round to even */
407 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
409 dataOffset = parmOffset + totalParms;
410 dataAlign = dataOffset & 2; /* quad-align */
411 dataOffset += dataAlign;
412 tp->datap = outp->data + dataOffset;
417 /* free a tran2 packet; must be called with smb_globalLock held */
418 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
420 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
421 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
430 /* called with a VC, an input packet to respond to, and an error code.
431 * sends an error response.
433 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
434 smb_packet_t *tp, long code)
437 unsigned short errCode;
438 unsigned char errClass;
439 unsigned long NTStatus;
441 if (vcp->flags & SMB_VCFLAG_STATUS32)
442 smb_MapNTError(code, &NTStatus);
444 smb_MapCoreError(code, vcp, &errCode, &errClass);
446 smb_FormatResponsePacket(vcp, NULL, tp);
449 /* We can handle long names */
450 if (vcp->flags & SMB_VCFLAG_USENT)
451 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
453 /* now copy important fields from the tran 2 packet */
454 smbp->com = 0x32; /* tran 2 response */
455 smbp->tid = t2p->tid;
456 smbp->mid = t2p->mid;
457 smbp->pid = t2p->pid;
458 smbp->uid = t2p->uid;
459 smbp->res[0] = t2p->res[0];
460 if (vcp->flags & SMB_VCFLAG_STATUS32) {
461 smbp->rcls = (unsigned char) (NTStatus & 0xff);
462 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
463 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
464 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
465 smbp->flg2 |= 0x4000;
468 smbp->rcls = errClass;
469 smbp->errLow = (unsigned char) (errCode & 0xff);
470 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
474 smb_SendPacket(vcp, tp);
477 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
480 unsigned short parmOffset;
481 unsigned short dataOffset;
482 unsigned short totalLength;
483 unsigned short dataAlign;
486 smb_FormatResponsePacket(vcp, NULL, tp);
489 /* We can handle long names */
490 if (vcp->flags & SMB_VCFLAG_USENT)
491 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
493 /* now copy important fields from the tran 2 packet */
494 smbp->com = 0x32; /* tran 2 response */
495 smbp->tid = t2p->tid;
496 smbp->mid = t2p->mid;
497 smbp->pid = t2p->pid;
498 smbp->uid = t2p->uid;
499 smbp->res[0] = t2p->res[0];
501 totalLength = 1 + t2p->totalData + t2p->totalParms;
503 /* now add the core parameters (tran2 info) to the packet */
504 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
505 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
506 smb_SetSMBParm(tp, 2, 0); /* reserved */
507 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
508 parmOffset = 10*2 + 35; /* parm offset in packet */
509 parmOffset++; /* round to even */
510 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
511 * hdr, bcc and wct */
512 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
513 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
514 dataOffset = parmOffset + t2p->oldTotalParms;
515 dataAlign = dataOffset & 2; /* quad-align */
516 dataOffset += dataAlign;
517 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
518 smb_SetSMBParm(tp, 8, 0); /* data displacement */
519 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
522 datap = smb_GetSMBData(tp, NULL);
523 *datap++ = 0; /* we rounded to even */
525 totalLength += dataAlign;
526 smb_SetSMBDataLength(tp, totalLength);
528 /* next, send the datagram */
529 smb_SendPacket(vcp, tp);
532 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
534 smb_tran2Packet_t *asp;
546 /* We sometimes see 0 word count. What to do? */
547 if (*inp->wctp == 0) {
552 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0");
554 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
555 ptbuf[0] = "Transaction2 word count = 0";
556 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
557 1, inp->ncb_length, ptbuf, inp);
558 DeregisterEventSource(h);
560 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0");
563 smb_SetSMBDataLength(outp, 0);
564 smb_SendPacket(vcp, outp);
568 totalParms = smb_GetSMBParm(inp, 0);
569 totalData = smb_GetSMBParm(inp, 1);
571 firstPacket = (inp->inCom == 0x32);
573 /* find the packet we're reassembling */
574 lock_ObtainWrite(&smb_globalLock);
575 asp = smb_FindTran2Packet(vcp, inp);
577 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
579 lock_ReleaseWrite(&smb_globalLock);
581 /* now merge in this latest packet; start by looking up offsets */
583 parmDisp = dataDisp = 0;
584 parmOffset = smb_GetSMBParm(inp, 10);
585 dataOffset = smb_GetSMBParm(inp, 12);
586 parmCount = smb_GetSMBParm(inp, 9);
587 dataCount = smb_GetSMBParm(inp, 11);
588 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
589 asp->maxReturnData = smb_GetSMBParm(inp, 3);
591 osi_Log3(afsd_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
592 totalData, dataCount, asp->maxReturnData);
595 parmDisp = smb_GetSMBParm(inp, 4);
596 parmOffset = smb_GetSMBParm(inp, 3);
597 dataDisp = smb_GetSMBParm(inp, 7);
598 dataOffset = smb_GetSMBParm(inp, 6);
599 parmCount = smb_GetSMBParm(inp, 2);
600 dataCount = smb_GetSMBParm(inp, 5);
602 osi_Log2(afsd_logp, "SMB3 received T2 aux packet parms %d, data %d",
603 parmCount, dataCount);
606 /* now copy the parms and data */
607 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
608 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
610 /* account for new bytes */
611 asp->curData += dataCount;
612 asp->curParms += parmCount;
614 /* finally, if we're done, remove the packet from the queue and dispatch it */
615 if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
616 /* we've received it all */
617 lock_ObtainWrite(&smb_globalLock);
618 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
619 lock_ReleaseWrite(&smb_globalLock);
621 /* now dispatch it */
622 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
624 /* if an error is returned, we're supposed to send an error packet,
625 * otherwise the dispatched function already did the data sending.
626 * We give dispatched proc the responsibility since it knows how much
630 smb_SendTran2Error(vcp, asp, outp, code);
633 /* free the input tran 2 packet */
634 lock_ObtainWrite(&smb_globalLock);
635 smb_FreeTran2Packet(asp);
636 lock_ReleaseWrite(&smb_globalLock);
638 else if (firstPacket) {
639 /* the first packet in a multi-packet request, we need to send an
640 * ack to get more data.
642 smb_SetSMBDataLength(outp, 0);
643 smb_SendPacket(vcp, outp);
649 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
652 smb_tran2Packet_t *outp;
657 cm_scache_t *dscp; /* dir we're dealing with */
658 cm_scache_t *scp; /* file we're creating */
670 int parmSlot; /* which parm we're dealing with */
679 extraInfo = (p->parmsp[0] & 1); /* return extra info */
680 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
682 openFun = p->parmsp[6]; /* open function */
683 excl = ((openFun & 3) == 0);
684 trunc = ((openFun & 3) == 2); /* truncate it */
685 openMode = (p->parmsp[1] & 0x7);
686 openAction = 0; /* tracks what we did */
688 attributes = p->parmsp[3];
689 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
691 /* compute initial mode bits based on read-only flag in attributes */
692 initialModeBits = 0666;
693 if (attributes & 1) initialModeBits &= ~0222;
695 pathp = (char *) (&p->parmsp[14]);
697 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
699 spacep = cm_GetSpace();
700 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
702 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
703 /* special case magic file name for receiving IOCTL requests
704 * (since IOCTL calls themselves aren't getting through).
706 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
707 smb_SetupIoctlFid(fidp, spacep);
709 /* copy out remainder of the parms */
711 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
713 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
714 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
715 outp->parmsp[parmSlot] = 0; parmSlot++;
716 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
717 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
718 outp->parmsp[parmSlot] = openMode; parmSlot++;
719 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
720 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
722 /* and the final "always present" stuff */
723 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
724 /* next write out the "unique" ID */
725 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
726 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
727 outp->parmsp[parmSlot] = 0; parmSlot++;
728 if (returnEALength) {
729 outp->parmsp[parmSlot] = 0; parmSlot++;
730 outp->parmsp[parmSlot] = 0; parmSlot++;
734 outp->totalParms = parmSlot * 2;
736 smb_SendTran2Packet(vcp, outp, op);
738 smb_FreeTran2Packet(outp);
740 /* and clean up fid reference */
741 smb_ReleaseFID(fidp);
745 userp = smb_GetTran2User(vcp, p);
746 tidPathp = smb_GetTIDPath(vcp, p->tid);
749 code = cm_NameI(cm_rootSCachep, pathp,
750 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
751 userp, tidPathp, &req, &scp);
753 code = cm_NameI(cm_rootSCachep, spacep->data,
754 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
755 userp, tidPathp, &req, &dscp);
756 cm_FreeSpace(spacep);
759 cm_ReleaseUser(userp);
760 smb_FreeTran2Packet(outp);
764 /* otherwise, scp points to the parent directory. Do a lookup,
765 * and truncate the file if we find it, otherwise we create the
768 if (!lastNamep) lastNamep = pathp;
770 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
772 if (code && code != CM_ERROR_NOSUCHFILE) {
773 cm_ReleaseSCache(dscp);
774 cm_ReleaseUser(userp);
775 smb_FreeTran2Packet(outp);
780 cm_FreeSpace(spacep);
783 /* if we get here, if code is 0, the file exists and is represented by
784 * scp. Otherwise, we have to create it.
787 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
789 if (dscp) cm_ReleaseSCache(dscp);
790 cm_ReleaseSCache(scp);
791 cm_ReleaseUser(userp);
792 smb_FreeTran2Packet(outp);
797 /* oops, file shouldn't be there */
798 if (dscp) cm_ReleaseSCache(dscp);
799 cm_ReleaseSCache(scp);
800 cm_ReleaseUser(userp);
801 smb_FreeTran2Packet(outp);
802 return CM_ERROR_EXISTS;
806 setAttr.mask = CM_ATTRMASK_LENGTH;
807 setAttr.length.LowPart = 0;
808 setAttr.length.HighPart = 0;
809 code = cm_SetAttr(scp, &setAttr, userp, &req);
810 openAction = 3; /* truncated existing file */
812 else openAction = 1; /* found existing file */
814 else if (!(openFun & 0x10)) {
815 /* don't create if not found */
816 if (dscp) cm_ReleaseSCache(dscp);
817 osi_assert(scp == NULL);
818 cm_ReleaseUser(userp);
819 smb_FreeTran2Packet(outp);
820 return CM_ERROR_NOSUCHFILE;
823 osi_assert(dscp != NULL && scp == NULL);
824 openAction = 2; /* created file */
825 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
826 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
827 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
829 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
830 smb_NotifyChange(FILE_ACTION_ADDED,
831 FILE_NOTIFY_CHANGE_FILE_NAME,
832 dscp, lastNamep, NULL, TRUE);
833 if (!excl && code == CM_ERROR_EXISTS) {
834 /* not an exclusive create, and someone else tried
835 * creating it already, then we open it anyway. We
836 * don't bother retrying after this, since if this next
837 * fails, that means that the file was deleted after we
840 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
844 setAttr.mask = CM_ATTRMASK_LENGTH;
845 setAttr.length.LowPart = 0;
846 setAttr.length.HighPart = 0;
847 code = cm_SetAttr(scp, &setAttr, userp,
850 } /* lookup succeeded */
854 /* we don't need this any longer */
855 if (dscp) cm_ReleaseSCache(dscp);
858 /* something went wrong creating or truncating the file */
859 if (scp) cm_ReleaseSCache(scp);
860 cm_ReleaseUser(userp);
861 smb_FreeTran2Packet(outp);
865 /* make sure we're about to open a file */
866 if (scp->fileType != CM_SCACHETYPE_FILE) {
867 cm_ReleaseSCache(scp);
868 cm_ReleaseUser(userp);
869 smb_FreeTran2Packet(outp);
870 return CM_ERROR_ISDIR;
873 /* now all we have to do is open the file itself */
874 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
877 /* save a pointer to the vnode */
880 /* compute open mode */
881 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
882 if (openMode == 1 || openMode == 2)
883 fidp->flags |= SMB_FID_OPENWRITE;
885 smb_ReleaseFID(fidp);
887 cm_Open(scp, 0, userp);
889 /* copy out remainder of the parms */
891 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
892 lock_ObtainMutex(&scp->mx);
894 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
895 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
896 outp->parmsp[parmSlot] = dosTime & 0xffff; parmSlot++;
897 outp->parmsp[parmSlot] = (dosTime>>16) & 0xffff; parmSlot++;
898 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
900 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
902 outp->parmsp[parmSlot] = openMode; parmSlot++;
903 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
904 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
906 /* and the final "always present" stuff */
907 outp->parmsp[parmSlot] = openAction; parmSlot++;
908 /* next write out the "unique" ID */
909 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
910 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
911 outp->parmsp[parmSlot] = 0; parmSlot++;
912 if (returnEALength) {
913 outp->parmsp[parmSlot] = 0; parmSlot++;
914 outp->parmsp[parmSlot] = 0; parmSlot++;
916 lock_ReleaseMutex(&scp->mx);
917 outp->totalData = 0; /* total # of data bytes */
918 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
920 smb_SendTran2Packet(vcp, outp, op);
922 smb_FreeTran2Packet(outp);
924 cm_ReleaseUser(userp);
925 /* leave scp held since we put it in fidp->scp */
929 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
931 return CM_ERROR_BADOP;
934 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
936 return CM_ERROR_BADOP;
939 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
941 smb_tran2Packet_t *outp;
942 smb_tran2QFSInfo_t qi;
945 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
947 osi_Log1(afsd_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
949 switch (p->parmsp[0]) {
950 case 1: responseSize = sizeof(qi.u.allocInfo); break;
951 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
952 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
953 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
954 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
955 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
956 default: return CM_ERROR_INVAL;
959 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
960 switch (p->parmsp[0]) {
963 qi.u.allocInfo.FSID = 0;
964 qi.u.allocInfo.sectorsPerAllocUnit = 1;
965 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
966 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
967 qi.u.allocInfo.bytesPerSector = 1024;
972 qi.u.volumeInfo.vsn = 1234;
973 qi.u.volumeInfo.vnCount = 4;
974 /* we're supposed to pad it out with zeroes to the end */
975 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
976 strcpy(qi.u.volumeInfo.label, "AFS");
981 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
982 qi.u.FSvolumeInfo.vsn = 1234;
983 qi.u.FSvolumeInfo.vnCount = 4;
984 strcpy(qi.u.FSvolumeInfo.label, "AFS");
990 temp.LowPart = 0x7fffffff;
991 qi.u.FSsizeInfo.totalAllocUnits = temp;
992 temp.LowPart = 0x3fffffff;
993 qi.u.FSsizeInfo.availAllocUnits = temp;
994 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
995 qi.u.FSsizeInfo.bytesPerSector = 1024;
1000 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
1001 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
1005 /* FS attribute info */
1006 /* attributes, defined in WINNT.H:
1007 * FILE_CASE_SENSITIVE_SEARCH 0x1
1008 * FILE_CASE_PRESERVED_NAMES 0x2
1009 * <no name defined> 0x4000
1010 * If bit 0x4000 is not set, Windows 95 thinks
1011 * we can't handle long (non-8.3) names,
1012 * despite our protestations to the contrary.
1014 qi.u.FSattributeInfo.attributes = 0x4003;
1015 qi.u.FSattributeInfo.maxCompLength = 255;
1016 qi.u.FSattributeInfo.FSnameLength = 6;
1017 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
1021 /* copy out return data, and set corresponding sizes */
1022 outp->totalParms = 0;
1023 outp->totalData = responseSize;
1024 memcpy(outp->datap, &qi, responseSize);
1026 /* send and free the packets */
1027 smb_SendTran2Packet(vcp, outp, op);
1028 smb_FreeTran2Packet(outp);
1033 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1035 return CM_ERROR_BADOP;
1038 struct smb_ShortNameRock {
1042 size_t shortNameLen;
1045 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
1048 struct smb_ShortNameRock *rockp;
1052 /* compare both names and vnodes, though probably just comparing vnodes
1053 * would be safe enough.
1055 if (stricmp(dep->name, rockp->maskp) != 0)
1057 if (ntohl(dep->fid.vnode) != rockp->vnode)
1059 /* This is the entry */
1060 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1061 rockp->shortNameLen = shortNameEnd - rockp->shortName;
1062 return CM_ERROR_STOPNOW;
1065 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1066 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1068 struct smb_ShortNameRock rock;
1072 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1076 spacep = cm_GetSpace();
1077 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1079 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1081 cm_FreeSpace(spacep);
1082 if (code) return code;
1084 if (!lastNamep) lastNamep = pathp;
1087 thyper.HighPart = 0;
1088 rock.shortName = shortName;
1090 rock.maskp = lastNamep;
1091 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1094 cm_ReleaseSCache(dscp);
1097 return CM_ERROR_NOSUCHFILE;
1098 if (code == CM_ERROR_STOPNOW) {
1099 *shortNameLenp = rock.shortNameLen;
1105 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1107 smb_tran2Packet_t *outp;
1108 unsigned long dosTime;
1110 unsigned short infoLevel;
1112 unsigned short attributes;
1113 unsigned long extAttributes;
1118 cm_scache_t *scp, *dscp;
1127 infoLevel = p->parmsp[0];
1128 if (infoLevel == 6) nbytesRequired = 0;
1129 else if (infoLevel == 1) nbytesRequired = 22;
1130 else if (infoLevel == 2) nbytesRequired = 26;
1131 else if (infoLevel == 0x101) nbytesRequired = 40;
1132 else if (infoLevel == 0x102) nbytesRequired = 24;
1133 else if (infoLevel == 0x103) nbytesRequired = 4;
1134 else if (infoLevel == 0x108) nbytesRequired = 30;
1136 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1137 p->opcode, infoLevel);
1138 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1141 osi_Log2(afsd_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1142 osi_LogSaveString(afsd_logp, (char *)(&p->parmsp[3])));
1144 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1146 if (infoLevel > 0x100)
1147 outp->totalParms = 2;
1149 outp->totalParms = 0;
1150 outp->totalData = nbytesRequired;
1152 /* now, if we're at infoLevel 6, we're only being asked to check
1153 * the syntax, so we just OK things now. In particular, we're *not*
1154 * being asked to verify anything about the state of any parent dirs.
1156 if (infoLevel == 6) {
1157 smb_SendTran2Packet(vcp, outp, opx);
1158 smb_FreeTran2Packet(outp);
1162 userp = smb_GetTran2User(vcp, p);
1164 tidPathp = smb_GetTIDPath(vcp, p->tid);
1167 * XXX Strange hack XXX
1169 * As of Patch 7 (13 January 98), we are having the following problem:
1170 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1171 * requests to look up "desktop.ini" in all the subdirectories.
1172 * This can cause zillions of timeouts looking up non-existent cells
1173 * and volumes, especially in the top-level directory.
1175 * We have not found any way to avoid this or work around it except
1176 * to explicitly ignore the requests for mount points that haven't
1177 * yet been evaluated and for directories that haven't yet been
1180 if (infoLevel == 0x101) {
1181 spacep = cm_GetSpace();
1182 smb_StripLastComponent(spacep->data, &lastComp,
1183 (char *)(&p->parmsp[3]));
1184 if (strcmp(lastComp, "\\desktop.ini") == 0) {
1185 code = cm_NameI(cm_rootSCachep, spacep->data,
1189 userp, tidPathp, &req, &dscp);
1191 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1192 && !dscp->mountRootFidp)
1193 code = CM_ERROR_NOSUCHFILE;
1194 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1195 cm_buf_t *bp = buf_Find(dscp, &hzero);
1199 code = CM_ERROR_NOSUCHFILE;
1201 cm_ReleaseSCache(dscp);
1203 cm_FreeSpace(spacep);
1204 cm_ReleaseUser(userp);
1205 smb_SendTran2Error(vcp, p, opx, code);
1206 smb_FreeTran2Packet(outp);
1211 cm_FreeSpace(spacep);
1214 /* now do namei and stat, and copy out the info */
1215 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1216 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1219 cm_ReleaseUser(userp);
1220 smb_SendTran2Error(vcp, p, opx, code);
1221 smb_FreeTran2Packet(outp);
1225 lock_ObtainMutex(&scp->mx);
1226 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1227 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1228 if (code) goto done;
1230 /* now we have the status in the cache entry, and everything is locked.
1231 * Marshall the output data.
1234 /* for info level 108, figure out short name */
1235 if (infoLevel == 0x108) {
1236 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1237 tidPathp, scp->fid.vnode, shortName,
1244 *((u_long *)op) = len * 2; op += 4;
1245 mbstowcs((unsigned short *)op, shortName, len);
1250 if (infoLevel == 1 || infoLevel == 2) {
1251 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1252 *((u_long *)op) = dosTime; op += 4; /* creation time */
1253 *((u_long *)op) = dosTime; op += 4; /* access time */
1254 *((u_long *)op) = dosTime; op += 4; /* write time */
1255 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1256 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1257 attributes = smb_Attributes(scp);
1258 *((u_short *)op) = attributes; op += 2; /* attributes */
1260 else if (infoLevel == 0x101) {
1261 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1262 *((FILETIME *)op) = ft; op += 8; /* creation time */
1263 *((FILETIME *)op) = ft; op += 8; /* last access time */
1264 *((FILETIME *)op) = ft; op += 8; /* last write time */
1265 *((FILETIME *)op) = ft; op += 8; /* last change time */
1266 extAttributes = smb_ExtAttributes(scp);
1267 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1268 *((u_long *)op) = 0; op += 4; /* don't know what this is */
1270 else if (infoLevel == 0x102) {
1271 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1272 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1273 *((u_long *)op) = scp->linkCount; op += 4;
1276 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1279 else if (infoLevel == 0x103) {
1280 memset(op, 0, 4); op += 4; /* EA size */
1283 /* now, if we are being asked about extended attrs, return a 0 size */
1284 if (infoLevel == 2) {
1285 *((u_long *)op) = 0; op += 4;
1289 /* send and free the packets */
1291 lock_ReleaseMutex(&scp->mx);
1292 cm_ReleaseSCache(scp);
1293 cm_ReleaseUser(userp);
1294 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1295 else smb_SendTran2Error(vcp, p, opx, code);
1296 smb_FreeTran2Packet(outp);
1301 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1303 return CM_ERROR_BADOP;
1306 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1308 smb_tran2Packet_t *outp;
1310 unsigned long attributes;
1311 unsigned short infoLevel;
1324 fidp = smb_FindFID(vcp, fid, 0);
1327 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
1331 infoLevel = p->parmsp[1];
1332 if (infoLevel == 0x101) nbytesRequired = 40;
1333 else if (infoLevel == 0x102) nbytesRequired = 24;
1334 else if (infoLevel == 0x103) nbytesRequired = 4;
1335 else if (infoLevel == 0x104) nbytesRequired = 6;
1337 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1338 p->opcode, infoLevel);
1339 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1342 osi_Log2(afsd_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1344 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1346 if (infoLevel > 0x100)
1347 outp->totalParms = 2;
1349 outp->totalParms = 0;
1350 outp->totalData = nbytesRequired;
1352 userp = smb_GetTran2User(vcp, p);
1355 lock_ObtainMutex(&scp->mx);
1356 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1357 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1358 if (code) goto done;
1360 /* now we have the status in the cache entry, and everything is locked.
1361 * Marshall the output data.
1364 if (infoLevel == 0x101) {
1365 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1366 *((FILETIME *)op) = ft; op += 8; /* creation time */
1367 *((FILETIME *)op) = ft; op += 8; /* last access time */
1368 *((FILETIME *)op) = ft; op += 8; /* last write time */
1369 *((FILETIME *)op) = ft; op += 8; /* last change time */
1370 attributes = smb_ExtAttributes(scp);
1371 *((u_long *)op) = attributes; op += 4;
1372 *((u_long *)op) = 0; op += 4;
1374 else if (infoLevel == 0x102) {
1375 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1376 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1377 *((u_long *)op) = scp->linkCount; op += 4;
1378 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1380 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1383 else if (infoLevel == 0x103) {
1384 *((u_long *)op) = 0; op += 4;
1386 else if (infoLevel == 0x104) {
1390 if (fidp->NTopen_wholepathp)
1391 name = fidp->NTopen_wholepathp;
1393 name = "\\"; /* probably can't happen */
1395 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
1396 *((u_long *)op) = len * 2; op += 4;
1397 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1400 /* send and free the packets */
1402 lock_ReleaseMutex(&scp->mx);
1403 cm_ReleaseUser(userp);
1404 smb_ReleaseFID(fidp);
1405 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1406 else smb_SendTran2Error(vcp, p, opx, code);
1407 smb_FreeTran2Packet(outp);
1412 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1417 unsigned short infoLevel;
1418 smb_tran2Packet_t *outp;
1426 fidp = smb_FindFID(vcp, fid, 0);
1429 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1433 infoLevel = p->parmsp[1];
1434 if (infoLevel > 0x104 || infoLevel < 0x101) {
1435 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1436 p->opcode, infoLevel);
1437 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1441 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1442 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1445 if ((infoLevel == 0x103 || infoLevel == 0x104)
1446 && !(fidp->flags & SMB_FID_OPENWRITE)) {
1447 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1451 osi_Log1(afsd_logp, "T2 SFileInfo type 0x%x", infoLevel);
1453 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1455 outp->totalParms = 2;
1456 outp->totalData = 0;
1458 userp = smb_GetTran2User(vcp, p);
1462 if (infoLevel == 0x101) {
1464 unsigned int attribute;
1467 /* lock the vnode with a callback; we need the current status
1468 * to determine what the new status is, in some cases.
1470 lock_ObtainMutex(&scp->mx);
1471 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1472 CM_SCACHESYNC_GETSTATUS
1473 | CM_SCACHESYNC_NEEDCALLBACK);
1475 lock_ReleaseMutex(&scp->mx);
1479 /* prepare for setattr call */
1481 lastMod = *((FILETIME *)(p->datap + 16));
1482 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod))) {
1483 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1484 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1486 fidp->flags |= SMB_FID_MTIMESETDONE;
1488 attribute = *((u_long *)(p->datap + 32));
1489 if (attribute != 0) {
1490 if ((scp->unixModeBits & 0222)
1491 && (attribute & 1) != 0) {
1492 /* make a writable file read-only */
1493 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1494 attr.unixModeBits = scp->unixModeBits & ~0222;
1496 else if ((scp->unixModeBits & 0222) == 0
1497 && (attribute & 1) == 0) {
1498 /* make a read-only file writable */
1499 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1500 attr.unixModeBits = scp->unixModeBits | 0222;
1503 lock_ReleaseMutex(&scp->mx);
1507 code = cm_SetAttr(scp, &attr, userp, &req);
1511 else if (infoLevel == 0x103 || infoLevel == 0x104) {
1512 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1515 attr.mask = CM_ATTRMASK_LENGTH;
1516 attr.length.LowPart = size.LowPart;
1517 attr.length.HighPart = size.HighPart;
1518 code = cm_SetAttr(scp, &attr, userp, &req);
1520 else if (infoLevel == 0x102) {
1521 if (*((char *)(p->datap))) {
1522 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1525 fidp->flags |= SMB_FID_DELONCLOSE;
1529 fidp->flags &= ~SMB_FID_DELONCLOSE;
1533 cm_ReleaseUser(userp);
1534 smb_ReleaseFID(fidp);
1535 if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1536 else smb_SendTran2Error(vcp, p, op, code);
1537 smb_FreeTran2Packet(outp);
1542 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1544 return CM_ERROR_BADOP;
1547 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1549 return CM_ERROR_BADOP;
1552 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1554 return CM_ERROR_BADOP;
1557 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1559 return CM_ERROR_BADOP;
1562 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1564 return CM_ERROR_BADOP;
1567 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1568 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1573 cm_scache_t *targetScp; /* target if scp is a symlink */
1578 unsigned short attr;
1579 unsigned long lattr;
1580 smb_dirListPatch_t *patchp;
1581 smb_dirListPatch_t *npatchp;
1583 for(patchp = *dirPatchespp; patchp; patchp =
1584 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1585 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1587 lock_ObtainMutex(&scp->mx);
1588 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1589 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1591 lock_ReleaseMutex(&scp->mx);
1592 cm_ReleaseSCache(scp);
1596 /* now watch for a symlink */
1597 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1598 lock_ReleaseMutex(&scp->mx);
1599 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp,
1602 /* we have a more accurate file to use (the
1603 * target of the symbolic link). Otherwise,
1604 * we'll just use the symlink anyway.
1606 osi_Log2(afsd_logp, "symlink vp %x to vp %x",
1608 cm_ReleaseSCache(scp);
1611 lock_ObtainMutex(&scp->mx);
1614 dptr = patchp->dptr;
1616 if (infoLevel >= 0x101) {
1618 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1620 /* copy to Creation Time */
1621 *((FILETIME *)dptr) = ft;
1624 /* copy to Last Access Time */
1625 *((FILETIME *)dptr) = ft;
1628 /* copy to Last Write Time */
1629 *((FILETIME *)dptr) = ft;
1632 /* copy to Change Time */
1633 *((FILETIME *)dptr) = ft;
1636 /* Use length for both file length and alloc length */
1637 *((LARGE_INTEGER *)dptr) = scp->length;
1639 *((LARGE_INTEGER *)dptr) = scp->length;
1642 /* Copy attributes */
1643 lattr = smb_ExtAttributes(scp);
1644 *((u_long *)dptr) = lattr;
1649 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1651 /* and copy out date */
1652 shortTemp = (dosTime>>16) & 0xffff;
1653 *((u_short *)dptr) = shortTemp;
1656 /* copy out creation time */
1657 shortTemp = dosTime & 0xffff;
1658 *((u_short *)dptr) = shortTemp;
1661 /* and copy out date */
1662 shortTemp = (dosTime>>16) & 0xffff;
1663 *((u_short *)dptr) = shortTemp;
1666 /* copy out access time */
1667 shortTemp = dosTime & 0xffff;
1668 *((u_short *)dptr) = shortTemp;
1671 /* and copy out date */
1672 shortTemp = (dosTime>>16) & 0xffff;
1673 *((u_short *)dptr) = shortTemp;
1676 /* copy out mod time */
1677 shortTemp = dosTime & 0xffff;
1678 *((u_short *)dptr) = shortTemp;
1681 /* copy out file length and alloc length,
1682 * using the same for both
1684 *((u_long *)dptr) = scp->length.LowPart;
1686 *((u_long *)dptr) = scp->length.LowPart;
1689 /* finally copy out attributes as short */
1690 attr = smb_Attributes(scp);
1691 *dptr++ = attr & 0xff;
1692 *dptr++ = (attr >> 8) & 0xff;
1695 lock_ReleaseMutex(&scp->mx);
1696 cm_ReleaseSCache(scp);
1699 /* now free the patches */
1700 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1701 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1705 /* and mark the list as empty */
1706 *dirPatchespp = NULL;
1711 /* do a case-folding search of the star name mask with the name in namep.
1712 * Return 1 if we match, otherwise 0.
1714 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1716 unsigned char tcp1, tcp2; /* Pattern characters */
1717 unsigned char tcn1; /* Name characters */
1718 int sawDot = 0, sawStar = 0;
1719 char *starNamep, *starMaskp;
1720 static char nullCharp[] = {0};
1722 /* make sure we only match 8.3 names, if requested */
1723 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) return 0;
1727 /* Next pattern character */
1730 /* Next name character */
1734 /* 0 - end of pattern */
1740 else if (tcp1 == '.' || tcp1 == '"') {
1750 * first dot in pattern;
1751 * must match dot or end of name
1756 else if (tcn1 == '.') {
1765 else if (tcp1 == '?') {
1766 if (tcn1 == 0 || tcn1 == '.')
1771 else if (tcp1 == '>') {
1772 if (tcn1 != 0 && tcn1 != '.')
1776 else if (tcp1 == '*' || tcp1 == '<') {
1780 else if (tcp2 == '.' || tcp2 == '"') {
1781 while (tcn1 != '.' && tcn1 != 0)
1796 * pattern character after '*' is not null or
1797 * period. If it is '?' or '>', we are not
1798 * going to understand it. If it is '*' or
1799 * '<', we are going to skip over it. None of
1800 * these are likely, I hope.
1802 /* skip over '*' and '<' */
1803 while (tcp2 == '*' || tcp2 == '<')
1806 /* skip over characters that don't match tcp2 */
1807 while (tcn1 != '.' && tcn1 != 0
1808 && cm_foldUpper[tcn1] != cm_foldUpper[tcp2])
1812 if (tcn1 == '.' || tcn1 == 0)
1815 /* Remember where we are */
1825 /* tcp1 is not a wildcard */
1826 if (cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) {
1831 /* if trying to match a star pattern, go back */
1833 maskp = starMaskp - 2;
1834 namep = starNamep + 1;
1844 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1853 smb_dirListPatch_t *dirListPatchesp;
1854 smb_dirListPatch_t *curPatchp;
1857 long orbytes; /* # of bytes in this output record */
1858 long ohbytes; /* # of bytes, except file name */
1859 long onbytes; /* # of bytes in name, incl. term. null */
1860 osi_hyper_t dirLength;
1861 osi_hyper_t bufferOffset;
1862 osi_hyper_t curOffset;
1864 smb_dirSearch_t *dsp;
1868 cm_pageHeader_t *pageHeaderp;
1869 cm_user_t *userp = NULL;
1872 long nextEntryCookie;
1873 int numDirChunks; /* # of 32 byte dir chunks in this entry */
1874 char *op; /* output data ptr */
1875 char *origOp; /* original value of op */
1876 cm_space_t *spacep; /* for pathname buffer */
1877 long maxReturnData; /* max # of return data */
1878 long maxReturnParms; /* max # of return parms */
1879 long bytesInBuffer; /* # data bytes in the output buffer */
1881 char *maskp; /* mask part of path */
1885 smb_tran2Packet_t *outp; /* response packet */
1888 char shortName[13]; /* 8.3 name if needed */
1899 if (p->opcode == 1) {
1900 /* find first; obtain basic parameters from request */
1901 attribute = p->parmsp[0];
1902 maxCount = p->parmsp[1];
1903 infoLevel = p->parmsp[3];
1904 searchFlags = p->parmsp[2];
1905 dsp = smb_NewDirSearch(1);
1906 dsp->attribute = attribute;
1907 pathp = ((char *) p->parmsp) + 12; /* points to path */
1909 maskp = strrchr(pathp, '\\');
1910 if (maskp == NULL) maskp = pathp;
1911 else maskp++; /* skip over backslash */
1912 strcpy(dsp->mask, maskp); /* and save mask */
1913 /* track if this is likely to match a lot of entries */
1914 starPattern = smb_V3IsStarMask(maskp);
1917 osi_assert(p->opcode == 2);
1918 /* find next; obtain basic parameters from request or open dir file */
1919 dsp = smb_FindDirSearch(p->parmsp[0]);
1920 if (!dsp) return CM_ERROR_BADFD;
1921 attribute = dsp->attribute;
1922 maxCount = p->parmsp[1];
1923 infoLevel = p->parmsp[2];
1924 searchFlags = p->parmsp[5];
1926 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
1928 starPattern = 1; /* assume, since required a Find Next */
1932 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
1933 attribute, infoLevel, maxCount, searchFlags);
1935 osi_Log2(afsd_logp, "...T2 search op %d, nextCookie 0x%x",
1936 p->opcode, nextCookie);
1938 if (infoLevel >= 0x101)
1939 searchFlags &= ~4; /* no resume keys */
1941 dirListPatchesp = NULL;
1943 maxReturnData = p->maxReturnData;
1944 if (p->opcode == 1) /* find first */
1945 maxReturnParms = 10; /* bytes */
1947 maxReturnParms = 8; /* bytes */
1949 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
1950 if (maxReturnData > 6000) maxReturnData = 6000;
1951 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
1953 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
1956 osi_Log1(afsd_logp, "T2 receive search dir %s",
1957 osi_LogSaveString(afsd_logp, pathp));
1959 /* bail out if request looks bad */
1960 if (p->opcode == 1 && !pathp) {
1961 return CM_ERROR_BADSMB;
1964 osi_Log2(afsd_logp, "T2 dir search cookie 0x%x, connection %d",
1965 nextCookie, dsp->cookie);
1967 userp = smb_GetTran2User(vcp, p);
1969 /* try to get the vnode for the path name next */
1970 lock_ObtainMutex(&dsp->mx);
1977 spacep = cm_GetSpace();
1978 smb_StripLastComponent(spacep->data, NULL, pathp);
1979 lock_ReleaseMutex(&dsp->mx);
1981 tidPathp = smb_GetTIDPath(vcp, p->tid);
1982 code = cm_NameI(cm_rootSCachep, spacep->data,
1983 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
1984 userp, tidPathp, &req, &scp);
1985 cm_FreeSpace(spacep);
1987 lock_ObtainMutex(&dsp->mx);
1989 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
1991 /* we need one hold for the entry we just stored into,
1992 * and one for our own processing. When we're done
1993 * with this function, we'll drop the one for our own
1994 * processing. We held it once from the namei call,
1995 * and so we do another hold now.
1998 lock_ObtainMutex(&scp->mx);
1999 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2000 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2001 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2002 dsp->flags |= SMB_DIRSEARCH_BULKST;
2004 lock_ReleaseMutex(&scp->mx);
2007 lock_ReleaseMutex(&dsp->mx);
2009 cm_ReleaseUser(userp);
2010 smb_FreeTran2Packet(outp);
2011 smb_DeleteDirSearch(dsp);
2012 smb_ReleaseDirSearch(dsp);
2016 /* get the directory size */
2017 lock_ObtainMutex(&scp->mx);
2018 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2019 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2021 lock_ReleaseMutex(&scp->mx);
2022 cm_ReleaseSCache(scp);
2023 cm_ReleaseUser(userp);
2024 smb_FreeTran2Packet(outp);
2025 smb_DeleteDirSearch(dsp);
2026 smb_ReleaseDirSearch(dsp);
2030 dirLength = scp->length;
2032 bufferOffset.LowPart = bufferOffset.HighPart = 0;
2033 curOffset.HighPart = 0;
2034 curOffset.LowPart = nextCookie;
2035 origOp = outp->datap;
2042 if (searchFlags & 4)
2043 /* skip over resume key */
2046 /* make sure that curOffset.LowPart doesn't point to the first
2047 * 32 bytes in the 2nd through last dir page, and that it doesn't
2048 * point at the first 13 32-byte chunks in the first dir page,
2049 * since those are dir and page headers, and don't contain useful
2052 temp = curOffset.LowPart & (2048-1);
2053 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2054 /* we're in the first page */
2055 if (temp < 13*32) temp = 13*32;
2058 /* we're in a later dir page */
2059 if (temp < 32) temp = 32;
2062 /* make sure the low order 5 bits are zero */
2065 /* now put temp bits back ito curOffset.LowPart */
2066 curOffset.LowPart &= ~(2048-1);
2067 curOffset.LowPart |= temp;
2069 /* check if we've returned all the names that will fit in the
2070 * response packet; we check return count as well as the number
2071 * of bytes requested. We check the # of bytes after we find
2072 * the dir entry, since we'll need to check its size.
2074 if (returnedNames >= maxCount) break;
2076 /* check if we've passed the dir's EOF */
2077 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2082 /* see if we can use the bufferp we have now; compute in which
2083 * page the current offset would be, and check whether that's
2084 * the offset of the buffer we have. If not, get the buffer.
2086 thyper.HighPart = curOffset.HighPart;
2087 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2088 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2091 buf_Release(bufferp);
2094 lock_ReleaseMutex(&scp->mx);
2095 lock_ObtainRead(&scp->bufCreateLock);
2096 code = buf_Get(scp, &thyper, &bufferp);
2097 lock_ReleaseRead(&scp->bufCreateLock);
2099 /* now, if we're doing a star match, do bulk fetching
2100 * of all of the status info for files in the dir.
2103 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2106 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2107 && LargeIntegerGreaterThanOrEqualTo(
2108 thyper, scp->bulkStatProgress)) {
2109 /* Don't bulk stat if risking timeout */
2110 int now = GetCurrentTime();
2111 if (now - req.startTime > 5000) {
2112 scp->bulkStatProgress = thyper;
2113 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2114 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2116 cm_TryBulkStat(scp, &thyper,
2121 lock_ObtainMutex(&scp->mx);
2123 bufferOffset = thyper;
2125 /* now get the data in the cache */
2127 code = cm_SyncOp(scp, bufferp, userp, &req,
2129 CM_SCACHESYNC_NEEDCALLBACK
2130 | CM_SCACHESYNC_READ);
2133 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2135 /* otherwise, load the buffer and try again */
2136 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2141 buf_Release(bufferp);
2145 } /* if (wrong buffer) ... */
2147 /* now we have the buffer containing the entry we're interested
2148 * in; copy it out if it represents a non-deleted entry.
2150 entryInDir = curOffset.LowPart & (2048-1);
2151 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2153 /* page header will help tell us which entries are free. Page
2154 * header can change more often than once per buffer, since
2155 * AFS 3 dir page size may be less than (but not more than)
2156 * a buffer package buffer.
2158 /* only look intra-buffer */
2159 temp = curOffset.LowPart & (buf_bufferSize - 1);
2160 temp &= ~(2048 - 1); /* turn off intra-page bits */
2161 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2163 /* now determine which entry we're looking at in the page.
2164 * If it is free (there's a free bitmap at the start of the
2165 * dir), we should skip these 32 bytes.
2167 slotInPage = (entryInDir & 0x7e0) >> 5;
2168 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2169 & (1 << (slotInPage & 0x7)))) {
2170 /* this entry is free */
2171 numDirChunks = 1; /* only skip this guy */
2175 tp = bufferp->datap + entryInBuffer;
2176 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
2178 /* while we're here, compute the next entry's location, too,
2179 * since we'll need it when writing out the cookie into the dir
2182 * XXXX Probably should do more sanity checking.
2184 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2186 /* compute offset of cookie representing next entry */
2187 nextEntryCookie = curOffset.LowPart
2188 + (CM_DIR_CHUNKSIZE * numDirChunks);
2190 /* Need 8.3 name? */
2192 if (infoLevel == 0x104
2193 && dep->fid.vnode != 0
2194 && !cm_Is8Dot3(dep->name)) {
2195 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2199 if (dep->fid.vnode != 0
2200 && (smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)
2202 && smb_V3MatchMask(shortName, maskp,
2203 CM_FLAG_CASEFOLD)))) {
2205 /* Eliminate entries that don't match requested
2207 if (!(dsp->attribute & 0x10)) /* no directories */
2209 /* We have already done the cm_TryBulkStat above */
2210 fid.cell = scp->fid.cell;
2211 fid.volume = scp->fid.volume;
2212 fid.vnode = ntohl(dep->fid.vnode);
2213 fid.unique = ntohl(dep->fid.unique);
2214 fileType = cm_FindFileType(&fid);
2215 /*osi_Log2(afsd_logp, "smb_ReceiveTran2SearchDir: file %s "
2216 "has filetype %d", dep->name,
2218 if (fileType == CM_SCACHETYPE_DIRECTORY)
2222 /* finally check if this name will fit */
2224 /* standard dir entry stuff */
2225 if (infoLevel < 0x101)
2226 ohbytes = 23; /* pre-NT */
2227 else if (infoLevel == 0x103)
2228 ohbytes = 12; /* NT names only */
2230 ohbytes = 64; /* NT */
2232 if (infoLevel == 0x104)
2233 ohbytes += 26; /* Short name & length */
2235 if (searchFlags & 4) {
2236 ohbytes += 4; /* if resume key required */
2240 && infoLevel != 0x101
2241 && infoLevel != 0x103)
2242 ohbytes += 4; /* EASIZE */
2244 /* add header to name & term. null */
2245 orbytes = onbytes + ohbytes + 1;
2247 /* now, we round up the record to a 4 byte alignment,
2248 * and we make sure that we have enough room here for
2249 * even the aligned version (so we don't have to worry
2250 * about an * overflow when we pad things out below).
2251 * That's the reason for the alignment arithmetic below.
2253 if (infoLevel >= 0x101)
2254 align = (4 - (orbytes & 3)) & 3;
2257 if (orbytes + bytesInBuffer + align > maxReturnData)
2260 /* this is one of the entries to use: it is not deleted
2261 * and it matches the star pattern we're looking for.
2262 * Put out the name, preceded by its length.
2264 /* First zero everything else */
2265 memset(origOp, 0, ohbytes);
2267 if (infoLevel <= 0x101)
2268 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2269 else if (infoLevel == 0x103)
2270 *((u_long *)(op + 8)) = onbytes;
2272 *((u_long *)(op + 60)) = onbytes;
2273 strcpy(origOp+ohbytes, dep->name);
2275 /* Short name if requested and needed */
2276 if (infoLevel == 0x104) {
2277 if (NeedShortName) {
2278 strcpy(op + 70, shortName);
2279 *(op + 68) = shortNameEnd - shortName;
2283 /* now, adjust the # of entries copied */
2286 /* NextEntryOffset and FileIndex */
2287 if (infoLevel >= 101) {
2288 int entryOffset = orbytes + align;
2289 *((u_long *)op) = entryOffset;
2290 *((u_long *)(op+4)) = nextEntryCookie;
2293 /* now we emit the attribute. This is tricky, since
2294 * we need to really stat the file to find out what
2295 * type of entry we've got. Right now, we're copying
2296 * out data from * a buffer, while holding the scp
2297 * locked, so it isn't really convenient to stat
2298 * something now. We'll put in a place holder
2299 * now, and make a second pass before returning this
2300 * to get the real attributes. So, we just skip the
2301 * data for now, and adjust it later. We allocate a
2302 * patch record to make it easy to find this point
2303 * later. The replay will happen at a time when it is
2304 * safe to unlock the directory.
2306 if (infoLevel != 0x103) {
2307 curPatchp = malloc(sizeof(*curPatchp));
2308 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2310 curPatchp->dptr = op;
2311 if (infoLevel >= 0x101)
2312 curPatchp->dptr += 8;
2313 curPatchp->fid.cell = scp->fid.cell;
2314 curPatchp->fid.volume = scp->fid.volume;
2315 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2316 curPatchp->fid.unique = ntohl(dep->fid.unique);
2319 curPatchp->dep = dep;
2322 if (searchFlags & 4)
2323 /* put out resume key */
2324 *((u_long *)origOp) = nextEntryCookie;
2326 /* Adjust byte ptr and count */
2327 origOp += orbytes; /* skip entire record */
2328 bytesInBuffer += orbytes;
2330 /* and pad the record out */
2331 while (--align >= 0) {
2336 } /* if we're including this name */
2339 /* and adjust curOffset to be where the new cookie is */
2340 thyper.HighPart = 0;
2341 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2342 curOffset = LargeIntegerAdd(thyper, curOffset);
2343 } /* while copying data for dir listing */
2345 /* release the mutex */
2346 lock_ReleaseMutex(&scp->mx);
2347 if (bufferp) buf_Release(bufferp);
2349 /* apply and free last set of patches; if not doing a star match, this
2350 * will be empty, but better safe (and freeing everything) than sorry.
2352 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2355 /* now put out the final parameters */
2356 if (returnedNames == 0) eos = 1;
2357 if (p->opcode == 1) {
2359 outp->parmsp[0] = (unsigned short) dsp->cookie;
2360 outp->parmsp[1] = returnedNames;
2361 outp->parmsp[2] = eos;
2362 outp->parmsp[3] = 0; /* nothing wrong with EAS */
2363 outp->parmsp[4] = 0; /* don't need last name to continue
2364 * search, cookie is enough. Normally,
2365 * this is the offset of the file name
2366 * of the last entry returned.
2368 outp->totalParms = 10; /* in bytes */
2372 outp->parmsp[0] = returnedNames;
2373 outp->parmsp[1] = eos;
2374 outp->parmsp[2] = 0; /* EAS error */
2375 outp->parmsp[3] = 0; /* last name, as above */
2376 outp->totalParms = 8; /* in bytes */
2379 /* return # of bytes in the buffer */
2380 outp->totalData = bytesInBuffer;
2382 osi_Log2(afsd_logp, "T2 search dir done, %d names, code %d",
2383 returnedNames, code);
2385 /* Return error code if unsuccessful on first request */
2386 if (code == 0 && p->opcode == 1 && returnedNames == 0)
2387 code = CM_ERROR_NOSUCHFILE;
2389 /* if we're supposed to close the search after this request, or if
2390 * we're supposed to close the search if we're done, and we're done,
2391 * or if something went wrong, close the search.
2393 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2394 if ((searchFlags & 1) || (returnedNames == 0)
2395 || code != 0) smb_DeleteDirSearch(dsp);
2397 smb_SendTran2Error(vcp, p, opx, code);
2399 smb_SendTran2Packet(vcp, outp, opx);
2401 smb_FreeTran2Packet(outp);
2402 smb_ReleaseDirSearch(dsp);
2403 cm_ReleaseSCache(scp);
2404 cm_ReleaseUser(userp);
2408 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2411 smb_dirSearch_t *dsp;
2413 dirHandle = smb_GetSMBParm(inp, 0);
2415 osi_Log1(afsd_logp, "SMB3 find close handle %d", dirHandle);
2417 dsp = smb_FindDirSearch(dirHandle);
2420 return CM_ERROR_BADFD;
2422 /* otherwise, we have an FD to destroy */
2423 smb_DeleteDirSearch(dsp);
2424 smb_ReleaseDirSearch(dsp);
2426 /* and return results */
2427 smb_SetSMBDataLength(outp, 0);
2432 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2434 smb_SetSMBDataLength(outp, 0);
2438 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2445 cm_scache_t *dscp; /* dir we're dealing with */
2446 cm_scache_t *scp; /* file we're creating */
2448 int initialModeBits;
2458 int parmSlot; /* which parm we're dealing with */
2466 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
2467 openFun = smb_GetSMBParm(inp, 8); /* open function */
2468 excl = ((openFun & 3) == 0);
2469 trunc = ((openFun & 3) == 2); /* truncate it */
2470 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2471 openAction = 0; /* tracks what we did */
2473 attributes = smb_GetSMBParm(inp, 5);
2474 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2476 /* compute initial mode bits based on read-only flag in attributes */
2477 initialModeBits = 0666;
2478 if (attributes & 1) initialModeBits &= ~0222;
2480 pathp = smb_GetSMBData(inp, NULL);
2482 spacep = inp->spacep;
2483 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2485 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2486 /* special case magic file name for receiving IOCTL requests
2487 * (since IOCTL calls themselves aren't getting through).
2489 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2490 smb_SetupIoctlFid(fidp, spacep);
2492 /* set inp->fid so that later read calls in same msg can find fid */
2493 inp->fid = fidp->fid;
2495 /* copy out remainder of the parms */
2497 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2499 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2500 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
2501 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2502 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
2503 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2504 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2505 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2506 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2508 /* and the final "always present" stuff */
2509 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2510 /* next write out the "unique" ID */
2511 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2512 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2513 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2514 smb_SetSMBDataLength(outp, 0);
2516 /* and clean up fid reference */
2517 smb_ReleaseFID(fidp);
2521 userp = smb_GetUser(vcp, inp);
2524 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2525 code = cm_NameI(cm_rootSCachep, pathp,
2526 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2527 userp, tidPathp, &req, &scp);
2529 code = cm_NameI(cm_rootSCachep, spacep->data,
2530 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2531 userp, tidPathp, &req, &dscp);
2534 cm_ReleaseUser(userp);
2538 /* otherwise, scp points to the parent directory. Do a lookup,
2539 * and truncate the file if we find it, otherwise we create the
2542 if (!lastNamep) lastNamep = pathp;
2544 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2546 if (code && code != CM_ERROR_NOSUCHFILE) {
2547 cm_ReleaseSCache(dscp);
2548 cm_ReleaseUser(userp);
2553 /* if we get here, if code is 0, the file exists and is represented by
2554 * scp. Otherwise, we have to create it. The dir may be represented
2555 * by dscp, or we may have found the file directly. If code is non-zero,
2559 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2561 if (dscp) cm_ReleaseSCache(dscp);
2562 cm_ReleaseSCache(scp);
2563 cm_ReleaseUser(userp);
2568 /* oops, file shouldn't be there */
2569 if (dscp) cm_ReleaseSCache(dscp);
2570 cm_ReleaseSCache(scp);
2571 cm_ReleaseUser(userp);
2572 return CM_ERROR_EXISTS;
2576 setAttr.mask = CM_ATTRMASK_LENGTH;
2577 setAttr.length.LowPart = 0;
2578 setAttr.length.HighPart = 0;
2579 code = cm_SetAttr(scp, &setAttr, userp, &req);
2580 openAction = 3; /* truncated existing file */
2582 else openAction = 1; /* found existing file */
2584 else if (!(openFun & 0x10)) {
2585 /* don't create if not found */
2586 if (dscp) cm_ReleaseSCache(dscp);
2587 cm_ReleaseUser(userp);
2588 return CM_ERROR_NOSUCHFILE;
2591 osi_assert(dscp != NULL);
2592 osi_Log1(afsd_logp, "smb_ReceiveV3OpenX creating file %s",
2593 osi_LogSaveString(afsd_logp, lastNamep));
2594 openAction = 2; /* created file */
2595 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2596 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2597 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2599 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2600 smb_NotifyChange(FILE_ACTION_ADDED,
2601 FILE_NOTIFY_CHANGE_FILE_NAME,
2602 dscp, lastNamep, NULL, TRUE);
2603 if (!excl && code == CM_ERROR_EXISTS) {
2604 /* not an exclusive create, and someone else tried
2605 * creating it already, then we open it anyway. We
2606 * don't bother retrying after this, since if this next
2607 * fails, that means that the file was deleted after we
2608 * started this call.
2610 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2614 setAttr.mask = CM_ATTRMASK_LENGTH;
2615 setAttr.length.LowPart = 0;
2616 setAttr.length.HighPart = 0;
2617 code = cm_SetAttr(scp, &setAttr, userp,
2620 } /* lookup succeeded */
2624 /* we don't need this any longer */
2625 if (dscp) cm_ReleaseSCache(dscp);
2628 /* something went wrong creating or truncating the file */
2629 if (scp) cm_ReleaseSCache(scp);
2630 cm_ReleaseUser(userp);
2634 /* make sure we're about to open a file */
2635 if (scp->fileType != CM_SCACHETYPE_FILE) {
2636 cm_ReleaseSCache(scp);
2637 cm_ReleaseUser(userp);
2638 return CM_ERROR_ISDIR;
2641 /* now all we have to do is open the file itself */
2642 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2645 /* save a pointer to the vnode */
2648 /* compute open mode */
2649 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2650 if (openMode == 1 || openMode == 2)
2651 fidp->flags |= SMB_FID_OPENWRITE;
2653 smb_ReleaseFID(fidp);
2655 cm_Open(scp, 0, userp);
2657 /* set inp->fid so that later read calls in same msg can find fid */
2658 inp->fid = fidp->fid;
2660 /* copy out remainder of the parms */
2662 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2663 lock_ObtainMutex(&scp->mx);
2665 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2666 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2667 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2668 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2669 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2670 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2671 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2672 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2673 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2675 /* and the final "always present" stuff */
2676 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2677 /* next write out the "unique" ID */
2678 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2679 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2680 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2681 lock_ReleaseMutex(&scp->mx);
2682 smb_SetSMBDataLength(outp, 0);
2684 osi_Log1(afsd_logp, "SMB OpenX opening fid %d", fidp->fid);
2686 cm_ReleaseUser(userp);
2687 /* leave scp held since we put it in fidp->scp */
2691 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2698 unsigned char LockType;
2699 unsigned short NumberOfUnlocks, NumberOfLocks;
2700 unsigned long Timeout;
2702 LARGE_INTEGER LOffset, LLength;
2703 smb_waitingLock_t *waitingLock;
2710 fid = smb_GetSMBParm(inp, 2);
2711 fid = smb_ChainFID(fid, inp);
2713 fidp = smb_FindFID(vcp, fid, 0);
2714 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2715 return CM_ERROR_BADFD;
2717 /* set inp->fid so that later read calls in same msg can find fid */
2720 userp = smb_GetUser(vcp, inp);
2724 lock_ObtainMutex(&scp->mx);
2725 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2726 CM_SCACHESYNC_NEEDCALLBACK
2727 | CM_SCACHESYNC_GETSTATUS
2728 | CM_SCACHESYNC_LOCK);
2729 if (code) goto doneSync;
2731 LockType = smb_GetSMBParm(inp, 3) & 0xff;
2732 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2733 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2734 NumberOfLocks = smb_GetSMBParm(inp, 7);
2736 op = smb_GetSMBData(inp, NULL);
2738 for (i=0; i<NumberOfUnlocks; 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 /* Do not check length -- length check done in cm_Unlock */
2759 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2760 if (code) goto done;
2763 for (i=0; i<NumberOfLocks; i++) {
2764 if (LockType & 0x10) {
2766 LOffset.HighPart = *((LONG *)(op + 4));
2767 LOffset.LowPart = *((DWORD *)(op + 8));
2768 LLength.HighPart = *((LONG *)(op + 12));
2769 LLength.LowPart = *((DWORD *)(op + 16));
2773 /* Not Large Files */
2774 LOffset.HighPart = 0;
2775 LOffset.LowPart = *((DWORD *)(op + 2));
2776 LLength.HighPart = 0;
2777 LLength.LowPart = *((DWORD *)(op + 6));
2780 if (LargeIntegerNotEqualToZero(LOffset))
2782 if (LargeIntegerLessThan(LOffset, scp->length))
2785 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2786 userp, &req, &lockp);
2787 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2788 /* Put on waiting list */
2789 waitingLock = malloc(sizeof(smb_waitingLock_t));
2790 waitingLock->vcp = vcp;
2791 waitingLock->inp = smb_CopyPacket(inp);
2792 waitingLock->outp = smb_CopyPacket(outp);
2793 waitingLock->timeRemaining = Timeout;
2794 waitingLock->lockp = lockp;
2795 lock_ObtainWrite(&smb_globalLock);
2796 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2798 osi_Wakeup((long) &smb_allWaitingLocks);
2799 lock_ReleaseWrite(&smb_globalLock);
2800 /* don't send reply immediately */
2801 outp->flags |= SMB_PACKETFLAG_NOSEND;
2807 /* release any locks acquired before the failure */
2810 smb_SetSMBDataLength(outp, 0);
2812 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2814 lock_ReleaseMutex(&scp->mx);
2815 cm_ReleaseUser(userp);
2816 smb_ReleaseFID(fidp);
2821 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2833 fid = smb_GetSMBParm(inp, 0);
2834 fid = smb_ChainFID(fid, inp);
2836 fidp = smb_FindFID(vcp, fid, 0);
2837 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2838 return CM_ERROR_BADFD;
2841 userp = smb_GetUser(vcp, inp);
2845 /* otherwise, stat the file */
2846 lock_ObtainMutex(&scp->mx);
2847 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2848 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2849 if (code) goto done;
2851 /* decode times. We need a search time, but the response to this
2852 * call provides the date first, not the time, as returned in the
2853 * searchTime variable. So we take the high-order bits first.
2855 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2856 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
2857 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2858 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
2859 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2860 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
2861 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2863 /* now handle file size and allocation size */
2864 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
2865 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2866 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
2867 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2869 /* file attribute */
2870 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2872 /* and finalize stuff */
2873 smb_SetSMBDataLength(outp, 0);
2877 lock_ReleaseMutex(&scp->mx);
2878 cm_ReleaseUser(userp);
2879 smb_ReleaseFID(fidp);
2883 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2897 fid = smb_GetSMBParm(inp, 0);
2898 fid = smb_ChainFID(fid, inp);
2900 fidp = smb_FindFID(vcp, fid, 0);
2901 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2902 return CM_ERROR_BADFD;
2905 userp = smb_GetUser(vcp, inp);
2909 /* now prepare to call cm_setattr. This message only sets various times,
2910 * and AFS only implements mtime, and we'll set the mtime if that's
2911 * requested. The others we'll ignore.
2913 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
2915 if (searchTime != 0) {
2916 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
2917 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
2918 attrs.clientModTime = unixTime;
2919 code = cm_SetAttr(scp, &attrs, userp, &req);
2923 cm_ReleaseUser(userp);
2924 smb_ReleaseFID(fidp);
2929 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2932 long count, finalCount;
2939 fd = smb_GetSMBParm(inp, 2);
2940 count = smb_GetSMBParm(inp, 5);
2941 offset.HighPart = 0; /* too bad */
2942 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
2944 osi_Log3(afsd_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
2945 fd, offset.LowPart, count);
2947 fd = smb_ChainFID(fd, inp);
2948 fidp = smb_FindFID(vcp, fd, 0);
2950 return CM_ERROR_BADFD;
2952 /* set inp->fid so that later read calls in same msg can find fid */
2955 if (fidp->flags & SMB_FID_IOCTL) {
2956 return smb_IoctlV3Read(fidp, vcp, inp, outp);
2959 userp = smb_GetUser(vcp, inp);
2961 /* 0 and 1 are reserved for request chaining, were setup by our caller,
2962 * and will be further filled in after we return.
2964 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
2965 smb_SetSMBParm(outp, 3, 0); /* resvd */
2966 smb_SetSMBParm(outp, 4, 0); /* resvd */
2967 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
2968 /* fill in #6 when we have all the parameters' space reserved */
2969 smb_SetSMBParm(outp, 7, 0); /* resv'd */
2970 smb_SetSMBParm(outp, 8, 0); /* resv'd */
2971 smb_SetSMBParm(outp, 9, 0); /* resv'd */
2972 smb_SetSMBParm(outp, 10, 0); /* resv'd */
2973 smb_SetSMBParm(outp, 11, 0); /* reserved */
2975 /* get op ptr after putting in the parms, since otherwise we don't
2976 * know where the data really is.
2978 op = smb_GetSMBData(outp, NULL);
2980 /* now fill in offset from start of SMB header to first data byte (to op) */
2981 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
2983 /* set the packet data length the count of the # of bytes */
2984 smb_SetSMBDataLength(outp, count);
2987 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
2989 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
2992 /* fix some things up */
2993 smb_SetSMBParm(outp, 5, finalCount);
2994 smb_SetSMBDataLength(outp, finalCount);
2996 smb_ReleaseFID(fidp);
2998 cm_ReleaseUser(userp);
3003 * Values for createDisp, copied from NTDDK.H
3005 * FILE_SUPERSEDE 0 (???)
3006 * FILE_OPEN 1 (open)
3007 * FILE_CREATE 2 (exclusive)
3008 * FILE_OPEN_IF 3 (non-exclusive)
3009 * FILE_OVERWRITE 4 (open & truncate, but do not create)
3010 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
3013 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3015 char *pathp, *realPathp;
3019 cm_scache_t *dscp; /* parent dir */
3020 cm_scache_t *scp; /* file to create or open */
3023 unsigned short nameLength;
3025 unsigned int requestOpLock;
3026 unsigned int requestBatchOpLock;
3027 unsigned int mustBeDir;
3029 unsigned int desiredAccess;
3030 unsigned int extAttributes;
3031 unsigned int createDisp;
3032 unsigned int createOptions;
3033 int initialModeBits;
3034 unsigned short baseFid;
3035 smb_fid_t *baseFidp;
3037 cm_scache_t *baseDirp;
3038 unsigned short openAction;
3052 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3053 flags = smb_GetSMBOffsetParm(inp, 3, 1)
3054 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3055 requestOpLock = flags & 0x02;
3056 requestBatchOpLock = flags & 0x04;
3057 mustBeDir = flags & 0x08;
3060 * Why all of a sudden 32-bit FID?
3061 * We will reject all bits higher than 16.
3063 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3064 return CM_ERROR_INVAL;
3065 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3066 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3067 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3068 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3069 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3070 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3071 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3072 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3073 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3075 /* mustBeDir is never set; createOptions directory bit seems to be
3078 if (createOptions & 1)
3080 else if (createOptions & 0x40)
3086 * compute initial mode bits based on read-only flag in
3087 * extended attributes
3089 initialModeBits = 0666;
3090 if (extAttributes & 1) initialModeBits &= ~0222;
3092 pathp = smb_GetSMBData(inp, NULL);
3093 /* Sometimes path is not null-terminated, so we make a copy. */
3094 realPathp = malloc(nameLength+1);
3095 memcpy(realPathp, pathp, nameLength);
3096 realPathp[nameLength] = 0;
3098 spacep = inp->spacep;
3099 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3101 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3102 /* special case magic file name for receiving IOCTL requests
3103 * (since IOCTL calls themselves aren't getting through).
3105 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3106 smb_SetupIoctlFid(fidp, spacep);
3108 /* set inp->fid so that later read calls in same msg can find fid */
3109 inp->fid = fidp->fid;
3113 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3114 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3115 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3117 memset(&ft, 0, sizeof(ft));
3118 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3119 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3120 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3121 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3122 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3123 sz.HighPart = 0x7fff; sz.LowPart = 0;
3124 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3125 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3126 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3127 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3128 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
3129 smb_SetSMBDataLength(outp, 0);
3131 /* clean up fid reference */
3132 smb_ReleaseFID(fidp);
3137 userp = smb_GetUser(vcp, inp);
3140 baseDirp = cm_rootSCachep;
3141 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3144 baseFidp = smb_FindFID(vcp, baseFid, 0);
3145 baseDirp = baseFidp->scp;
3149 /* compute open mode */
3151 if (desiredAccess & DELETE)
3152 fidflags |= SMB_FID_OPENDELETE;
3153 if (desiredAccess & AFS_ACCESS_READ)
3154 fidflags |= SMB_FID_OPENREAD;
3155 if (desiredAccess & AFS_ACCESS_WRITE)
3156 fidflags |= SMB_FID_OPENWRITE;
3160 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3161 userp, tidPathp, &req, &scp);
3162 if (code == 0) foundscp = TRUE;
3164 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3165 /* look up parent directory */
3166 code = cm_NameI(baseDirp, spacep->data,
3167 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3168 userp, tidPathp, &req, &dscp);
3170 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3173 cm_ReleaseUser(userp);
3178 if (!lastNamep) lastNamep = realPathp;
3181 if (!smb_IsLegalFilename(lastNamep))
3182 return CM_ERROR_BADNTFILENAME;
3185 code = cm_Lookup(dscp, lastNamep,
3186 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3188 if (code && code != CM_ERROR_NOSUCHFILE) {
3189 cm_ReleaseSCache(dscp);
3190 cm_ReleaseUser(userp);
3197 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3200 /* if we get here, if code is 0, the file exists and is represented by
3201 * scp. Otherwise, we have to create it. The dir may be represented
3202 * by dscp, or we may have found the file directly. If code is non-zero,
3206 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3209 if (dscp) cm_ReleaseSCache(dscp);
3210 cm_ReleaseSCache(scp);
3211 cm_ReleaseUser(userp);
3216 if (createDisp == 2) {
3217 /* oops, file shouldn't be there */
3218 if (dscp) cm_ReleaseSCache(dscp);
3219 cm_ReleaseSCache(scp);
3220 cm_ReleaseUser(userp);
3222 return CM_ERROR_EXISTS;
3226 || createDisp == 5) {
3227 setAttr.mask = CM_ATTRMASK_LENGTH;
3228 setAttr.length.LowPart = 0;
3229 setAttr.length.HighPart = 0;
3230 code = cm_SetAttr(scp, &setAttr, userp, &req);
3231 openAction = 3; /* truncated existing file */
3233 else openAction = 1; /* found existing file */
3235 else if (createDisp == 1 || createDisp == 4) {
3236 /* don't create if not found */
3237 if (dscp) cm_ReleaseSCache(dscp);
3238 cm_ReleaseUser(userp);
3240 return CM_ERROR_NOSUCHFILE;
3242 else if (realDirFlag == 0 || realDirFlag == -1) {
3243 osi_assert(dscp != NULL);
3244 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating file %s",
3245 osi_LogSaveString(afsd_logp, lastNamep));
3246 openAction = 2; /* created file */
3247 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3248 setAttr.clientModTime = time(NULL);
3249 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3251 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3252 smb_NotifyChange(FILE_ACTION_ADDED,
3253 FILE_NOTIFY_CHANGE_FILE_NAME,
3254 dscp, lastNamep, NULL, TRUE);
3255 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3256 /* Not an exclusive create, and someone else tried
3257 * creating it already, then we open it anyway. We
3258 * don't bother retrying after this, since if this next
3259 * fails, that means that the file was deleted after we
3260 * started this call.
3262 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3265 if (createDisp == 5) {
3266 setAttr.mask = CM_ATTRMASK_LENGTH;
3267 setAttr.length.LowPart = 0;
3268 setAttr.length.HighPart = 0;
3269 code = cm_SetAttr(scp, &setAttr, userp,
3272 } /* lookup succeeded */
3276 /* create directory */
3277 osi_assert(dscp != NULL);
3278 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating directory %s",
3279 osi_LogSaveString(afsd_logp, lastNamep));
3280 openAction = 2; /* created directory */
3281 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3282 setAttr.clientModTime = time(NULL);
3283 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3284 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3285 smb_NotifyChange(FILE_ACTION_ADDED,
3286 FILE_NOTIFY_CHANGE_DIR_NAME,
3287 dscp, lastNamep, NULL, TRUE);
3289 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3290 /* Not an exclusive create, and someone else tried
3291 * creating it already, then we open it anyway. We
3292 * don't bother retrying after this, since if this next
3293 * fails, that means that the file was deleted after we
3294 * started this call.
3296 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3302 /* something went wrong creating or truncating the file */
3303 if (scp) cm_ReleaseSCache(scp);
3304 cm_ReleaseUser(userp);
3309 /* make sure we have file vs. dir right */
3310 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3311 cm_ReleaseSCache(scp);
3312 cm_ReleaseUser(userp);
3314 return CM_ERROR_ISDIR;
3316 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3317 cm_ReleaseSCache(scp);
3318 cm_ReleaseUser(userp);
3320 return CM_ERROR_NOTDIR;
3323 /* open the file itself */
3324 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3326 /* save a pointer to the vnode */
3329 fidp->flags = fidflags;
3331 /* save parent dir and pathname for delete or change notification */
3332 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3333 fidp->flags |= SMB_FID_NTOPEN;
3334 fidp->NTopen_dscp = dscp;
3335 cm_HoldSCache(dscp);
3336 fidp->NTopen_pathp = strdup(lastNamep);
3338 fidp->NTopen_wholepathp = realPathp;
3340 /* we don't need this any longer */
3341 if (dscp) cm_ReleaseSCache(dscp);
3342 cm_Open(scp, 0, userp);
3344 /* set inp->fid so that later read calls in same msg can find fid */
3345 inp->fid = fidp->fid;
3349 lock_ObtainMutex(&scp->mx);
3350 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3351 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3352 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3353 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3354 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3355 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3356 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3357 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3358 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3360 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3361 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3362 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3363 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3364 smb_SetSMBParmByte(outp, parmSlot,
3365 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3366 lock_ReleaseMutex(&scp->mx);
3367 smb_SetSMBDataLength(outp, 0);
3369 osi_Log2(afsd_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3370 osi_LogSaveString(afsd_logp, realPathp));
3372 smb_ReleaseFID(fidp);
3374 cm_ReleaseUser(userp);
3376 /* leave scp held since we put it in fidp->scp */
3381 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3382 * Instead, ultimately, would like to use a subroutine for common code.
3384 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3386 char *pathp, *realPathp;
3390 cm_scache_t *dscp; /* parent dir */
3391 cm_scache_t *scp; /* file to create or open */
3394 unsigned long nameLength;
3396 unsigned int requestOpLock;
3397 unsigned int requestBatchOpLock;
3398 unsigned int mustBeDir;
3400 unsigned int desiredAccess;
3401 unsigned int extAttributes;
3402 unsigned int createDisp;
3403 unsigned int createOptions;
3404 int initialModeBits;
3405 unsigned short baseFid;
3406 smb_fid_t *baseFidp;
3408 cm_scache_t *baseDirp;
3409 unsigned short openAction;
3415 int parmOffset, dataOffset;
3426 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3427 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3428 parmp = inp->data + parmOffset;
3429 lparmp = (ULONG *) parmp;
3432 requestOpLock = flags & 0x02;
3433 requestBatchOpLock = flags & 0x04;
3434 mustBeDir = flags & 0x08;
3436 * Why all of a sudden 32-bit FID?
3437 * We will reject all bits higher than 16.
3439 if (lparmp[1] & 0xFFFF0000)
3440 return CM_ERROR_INVAL;
3441 baseFid = (unsigned short)lparmp[1];
3442 desiredAccess = lparmp[2];
3443 extAttributes = lparmp[5];
3444 createDisp = lparmp[7];
3445 createOptions = lparmp[8];
3446 nameLength = lparmp[11];
3448 /* mustBeDir is never set; createOptions directory bit seems to be
3451 if (createOptions & 1)
3453 else if (createOptions & 0x40)
3459 * compute initial mode bits based on read-only flag in
3460 * extended attributes
3462 initialModeBits = 0666;
3463 if (extAttributes & 1) initialModeBits &= ~0222;
3465 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3466 /* Sometimes path is not null-terminated, so we make a copy. */
3467 realPathp = malloc(nameLength+1);
3468 memcpy(realPathp, pathp, nameLength);
3469 realPathp[nameLength] = 0;
3471 spacep = cm_GetSpace();
3472 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3475 * Nothing here to handle SMB_IOCTL_FILENAME.
3476 * Will add it if necessary.
3479 userp = smb_GetUser(vcp, inp);
3482 baseDirp = cm_rootSCachep;
3483 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3486 baseFidp = smb_FindFID(vcp, baseFid, 0);
3487 baseDirp = baseFidp->scp;
3491 /* compute open mode */
3493 if (desiredAccess & DELETE)
3494 fidflags |= SMB_FID_OPENDELETE;
3495 if (desiredAccess & AFS_ACCESS_READ)
3496 fidflags |= SMB_FID_OPENREAD;
3497 if (desiredAccess & AFS_ACCESS_WRITE)
3498 fidflags |= SMB_FID_OPENWRITE;
3502 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3503 userp, tidPathp, &req, &scp);
3504 if (code == 0) foundscp = TRUE;
3506 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3507 /* look up parent directory */
3508 code = cm_NameI(baseDirp, spacep->data,
3509 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3510 userp, tidPathp, &req, &dscp);
3511 cm_FreeSpace(spacep);
3513 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3516 cm_ReleaseUser(userp);
3521 if (!lastNamep) lastNamep = realPathp;
3524 if (!smb_IsLegalFilename(lastNamep))
3525 return CM_ERROR_BADNTFILENAME;
3528 code = cm_Lookup(dscp, lastNamep,
3529 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3531 if (code && code != CM_ERROR_NOSUCHFILE) {
3532 cm_ReleaseSCache(dscp);
3533 cm_ReleaseUser(userp);
3540 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3541 cm_FreeSpace(spacep);
3544 /* if we get here, if code is 0, the file exists and is represented by
3545 * scp. Otherwise, we have to create it. The dir may be represented
3546 * by dscp, or we may have found the file directly. If code is non-zero,
3550 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3553 if (dscp) cm_ReleaseSCache(dscp);
3554 cm_ReleaseSCache(scp);
3555 cm_ReleaseUser(userp);
3560 if (createDisp == 2) {
3561 /* oops, file shouldn't be there */
3562 if (dscp) cm_ReleaseSCache(dscp);
3563 cm_ReleaseSCache(scp);
3564 cm_ReleaseUser(userp);
3566 return CM_ERROR_EXISTS;
3570 || createDisp == 5) {
3571 setAttr.mask = CM_ATTRMASK_LENGTH;
3572 setAttr.length.LowPart = 0;
3573 setAttr.length.HighPart = 0;
3574 code = cm_SetAttr(scp, &setAttr, userp, &req);
3575 openAction = 3; /* truncated existing file */
3577 else openAction = 1; /* found existing file */
3579 else if (createDisp == 1 || createDisp == 4) {
3580 /* don't create if not found */
3581 if (dscp) cm_ReleaseSCache(dscp);
3582 cm_ReleaseUser(userp);
3584 return CM_ERROR_NOSUCHFILE;
3586 else if (realDirFlag == 0 || realDirFlag == -1) {
3587 osi_assert(dscp != NULL);
3588 osi_Log1(afsd_logp, "smb_ReceiveNTTranCreate creating file %s",
3589 osi_LogSaveString(afsd_logp, lastNamep));
3590 openAction = 2; /* created file */
3591 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3592 setAttr.clientModTime = time(NULL);
3593 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3595 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3596 smb_NotifyChange(FILE_ACTION_ADDED,
3597 FILE_NOTIFY_CHANGE_FILE_NAME,
3598 dscp, lastNamep, NULL, TRUE);
3599 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3600 /* Not an exclusive create, and someone else tried
3601 * creating it already, then we open it anyway. We
3602 * don't bother retrying after this, since if this next
3603 * fails, that means that the file was deleted after we
3604 * started this call.
3606 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3609 if (createDisp == 5) {
3610 setAttr.mask = CM_ATTRMASK_LENGTH;
3611 setAttr.length.LowPart = 0;
3612 setAttr.length.HighPart = 0;
3613 code = cm_SetAttr(scp, &setAttr, userp,
3616 } /* lookup succeeded */
3620 /* create directory */
3621 osi_assert(dscp != NULL);
3623 "smb_ReceiveNTTranCreate creating directory %s",
3624 osi_LogSaveString(afsd_logp, lastNamep));
3625 openAction = 2; /* created directory */
3626 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3627 setAttr.clientModTime = time(NULL);
3628 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3629 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3630 smb_NotifyChange(FILE_ACTION_ADDED,
3631 FILE_NOTIFY_CHANGE_DIR_NAME,
3632 dscp, lastNamep, NULL, TRUE);
3634 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3635 /* Not an exclusive create, and someone else tried
3636 * creating it already, then we open it anyway. We
3637 * don't bother retrying after this, since if this next
3638 * fails, that means that the file was deleted after we
3639 * started this call.
3641 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3647 /* something went wrong creating or truncating the file */
3648 if (scp) cm_ReleaseSCache(scp);
3649 cm_ReleaseUser(userp);
3654 /* make sure we have file vs. dir right */
3655 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3656 cm_ReleaseSCache(scp);
3657 cm_ReleaseUser(userp);
3659 return CM_ERROR_ISDIR;
3661 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3662 cm_ReleaseSCache(scp);
3663 cm_ReleaseUser(userp);
3665 return CM_ERROR_NOTDIR;
3668 /* open the file itself */
3669 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3672 /* save a pointer to the vnode */
3675 fidp->flags = fidflags;
3677 /* save parent dir and pathname for deletion or change notification */
3678 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3679 fidp->flags |= SMB_FID_NTOPEN;
3680 fidp->NTopen_dscp = dscp;
3681 cm_HoldSCache(dscp);
3682 fidp->NTopen_pathp = strdup(lastNamep);
3684 fidp->NTopen_wholepathp = realPathp;
3686 /* we don't need this any longer */
3687 if (dscp) cm_ReleaseSCache(dscp);
3689 cm_Open(scp, 0, userp);
3691 /* set inp->fid so that later read calls in same msg can find fid */
3692 inp->fid = fidp->fid;
3695 parmOffset = 8*4 + 39;
3696 parmOffset += 1; /* pad to 4 */
3697 dataOffset = parmOffset + 70;
3701 /* Total Parameter Count */
3702 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3703 /* Total Data Count */
3704 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3705 /* Parameter Count */
3706 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3707 /* Parameter Offset */
3708 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3709 /* Parameter Displacement */
3710 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3712 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3714 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3715 /* Data Displacement */
3716 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3717 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
3718 smb_SetSMBDataLength(outp, 70);
3720 lock_ObtainMutex(&scp->mx);
3721 outData = smb_GetSMBData(outp, NULL);
3722 outData++; /* round to get to parmOffset */
3723 *outData = 0; outData++; /* oplock */
3724 *outData = 0; outData++; /* reserved */
3725 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
3726 *((ULONG *)outData) = openAction; outData += 4;
3727 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
3728 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3729 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
3730 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
3731 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
3732 *((FILETIME *)outData) = ft; outData += 8; /* change time */
3733 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
3734 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
3735 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
3736 *((USHORT *)outData) = 0; outData += 2; /* filetype */
3737 *((USHORT *)outData) = 0; outData += 2; /* dev state */
3738 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
3739 outData += 2; /* is a dir? */
3740 lock_ReleaseMutex(&scp->mx);
3742 osi_Log1(afsd_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
3744 smb_ReleaseFID(fidp);
3746 cm_ReleaseUser(userp);
3748 /* leave scp held since we put it in fidp->scp */
3752 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
3755 smb_packet_t *savedPacketp;
3756 ULONG filter; USHORT fid, watchtree;
3760 filter = smb_GetSMBParm(inp, 19)
3761 | (smb_GetSMBParm(inp, 20) << 16);
3762 fid = smb_GetSMBParm(inp, 21);
3763 watchtree = smb_GetSMBParm(inp, 22) && 0xffff;
3765 savedPacketp = smb_CopyPacket(inp);
3766 savedPacketp->vcp = vcp;
3767 lock_ObtainMutex(&smb_Dir_Watch_Lock);
3768 savedPacketp->nextp = smb_Directory_Watches;
3769 smb_Directory_Watches = savedPacketp;
3770 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
3772 fidp = smb_FindFID(vcp, fid, 0);
3774 osi_Log4(afsd_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
3775 filter, fid, watchtree, osi_LogSaveString(afsd_logp, fidp->NTopen_wholepathp));
3778 lock_ObtainMutex(&scp->mx);
3780 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
3782 scp->flags |= CM_SCACHEFLAG_WATCHED;
3783 lock_ReleaseMutex(&scp->mx);
3784 smb_ReleaseFID(fidp);
3786 outp->flags |= SMB_PACKETFLAG_NOSEND;
3791 unsigned char nullSecurityDesc[36] = {
3792 0x01, /* security descriptor revision */
3793 0x00, /* reserved, should be zero */
3794 0x00, 0x80, /* security descriptor control;
3795 * 0x8000 : self-relative format */
3796 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
3797 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
3798 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
3799 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
3800 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3801 /* "null SID" owner SID */
3802 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
3803 /* "null SID" group SID */
3806 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3808 int parmOffset, parmCount, dataOffset, dataCount;
3816 ULONG securityInformation;
3818 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3819 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3820 parmp = inp->data + parmOffset;
3821 sparmp = (USHORT *) parmp;
3822 lparmp = (ULONG *) parmp;
3825 securityInformation = lparmp[1];
3827 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
3828 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3836 parmOffset = 8*4 + 39;
3837 parmOffset += 1; /* pad to 4 */
3839 dataOffset = parmOffset + parmCount;
3843 /* Total Parameter Count */
3844 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
3845 /* Total Data Count */
3846 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
3847 /* Parameter Count */
3848 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
3849 /* Parameter Offset */
3850 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3851 /* Parameter Displacement */
3852 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3854 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
3856 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3857 /* Data Displacement */
3858 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3859 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
3860 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
3862 outData = smb_GetSMBData(outp, NULL);
3863 outData++; /* round to get to parmOffset */
3864 *((ULONG *)outData) = 36; outData += 4; /* length */
3866 if (maxData >= 36) {
3867 memcpy(outData, nullSecurityDesc, 36);
3871 return CM_ERROR_BUFFERTOOSMALL;
3874 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3876 unsigned short function;
3878 function = smb_GetSMBParm(inp, 18);
3880 osi_Log1(afsd_logp, "SMB NT Transact function %d", function);
3882 /* We can handle long names */
3883 if (vcp->flags & SMB_VCFLAG_USENT)
3884 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3888 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
3890 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
3892 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
3894 default: return CM_ERROR_INVAL;
3899 * smb_NotifyChange -- find relevant change notification messages and
3902 * If we don't know the file name (i.e. a callback break), filename is
3903 * NULL, and we return a zero-length list.
3905 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
3906 cm_scache_t *dscp, char *filename, char *otherFilename,
3907 BOOL isDirectParent)
3909 smb_packet_t *watch, *lastWatch, *nextWatch;
3910 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
3911 char *outData, *oldOutData;
3915 BOOL twoEntries = FALSE;
3916 ULONG otherNameLen, oldParmCount = 0;
3921 /* Get ready for rename within directory */
3922 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
3924 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
3927 lock_ObtainMutex(&smb_Dir_Watch_Lock);
3928 watch = smb_Directory_Watches;
3930 filter = smb_GetSMBParm(watch, 19)
3931 | (smb_GetSMBParm(watch, 20) << 16);
3932 fid = smb_GetSMBParm(watch, 21);
3933 wtree = smb_GetSMBParm(watch, 22) & 0xffff;
3934 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
3935 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
3939 * Strange hack - bug in NT Client and NT Server that we
3942 if (filter == 3 && wtree)
3945 fidp = smb_FindFID(vcp, fid, 0);
3946 if (fidp->scp != dscp
3947 || (filter & notifyFilter) == 0
3948 || (!isDirectParent && !wtree)) {
3949 smb_ReleaseFID(fidp);
3951 watch = watch->nextp;
3954 smb_ReleaseFID(fidp);
3957 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
3958 fid, filter, wtree, osi_LogSaveString(afsd_logp, filename));
3960 nextWatch = watch->nextp;
3961 if (watch == smb_Directory_Watches)
3962 smb_Directory_Watches = nextWatch;
3964 lastWatch->nextp = nextWatch;
3966 /* Turn off WATCHED flag in dscp */
3967 lock_ObtainMutex(&dscp->mx);
3969 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
3971 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
3972 lock_ReleaseMutex(&dscp->mx);
3974 /* Convert to response packet */
3975 ((smb_t *) watch)->reb = 0x80;
3976 ((smb_t *) watch)->wct = 0;
3979 if (filename == NULL)
3982 nameLen = strlen(filename);
3983 parmCount = 3*4 + nameLen*2;
3984 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
3986 otherNameLen = strlen(otherFilename);
3987 oldParmCount = parmCount;
3988 parmCount += 3*4 + otherNameLen*2;
3989 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
3991 if (maxLen < parmCount)
3992 parmCount = 0; /* not enough room */
3994 parmOffset = 8*4 + 39;
3995 parmOffset += 1; /* pad to 4 */
3996 dataOffset = parmOffset + parmCount;
4000 /* Total Parameter Count */
4001 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4002 /* Total Data Count */
4003 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4004 /* Parameter Count */
4005 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4006 /* Parameter Offset */
4007 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
4008 /* Parameter Displacement */
4009 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4011 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4013 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
4014 /* Data Displacement */
4015 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4016 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
4017 smb_SetSMBDataLength(watch, parmCount + 1);
4019 if (parmCount != 0) {
4020 outData = smb_GetSMBData(watch, NULL);
4021 outData++; /* round to get to parmOffset */
4022 oldOutData = outData;
4023 *((DWORD *)outData) = oldParmCount; outData += 4;
4024 /* Next Entry Offset */
4025 *((DWORD *)outData) = action; outData += 4;
4027 *((DWORD *)outData) = nameLen*2; outData += 4;
4028 /* File Name Length */
4029 mbstowcs((WCHAR *)outData, filename, nameLen);
4032 outData = oldOutData + oldParmCount;
4033 *((DWORD *)outData) = 0; outData += 4;
4034 /* Next Entry Offset */
4035 *((DWORD *)outData) = otherAction; outData += 4;
4037 *((DWORD *)outData) = otherNameLen*2;
4038 outData += 4; /* File Name Length */
4039 mbstowcs((WCHAR *)outData, otherFilename,
4040 otherNameLen); /* File Name */
4045 * If filename is null, we don't know the cause of the
4046 * change notification. We return zero data (see above),
4047 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
4048 * (= 0x010C). We set the error code here by hand, without
4049 * modifying wct and bcc.
4051 if (filename == NULL) {
4052 ((smb_t *) watch)->rcls = 0x0C;
4053 ((smb_t *) watch)->reh = 0x01;
4054 ((smb_t *) watch)->errLow = 0;
4055 ((smb_t *) watch)->errHigh = 0;
4056 /* Set NT Status codes flag */
4057 ((smb_t *) watch)->flg2 |= 0x4000;
4060 smb_SendPacket(vcp, watch);
4061 smb_FreePacket(watch);
4064 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4067 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4069 unsigned char *replyWctp;
4070 smb_packet_t *watch, *lastWatch;
4071 USHORT fid, watchtree;
4075 osi_Log0(afsd_logp, "SMB3 receive NT cancel");
4077 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4078 watch = smb_Directory_Watches;
4080 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
4081 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
4082 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
4083 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
4084 if (watch == smb_Directory_Watches)
4085 smb_Directory_Watches = watch->nextp;
4087 lastWatch->nextp = watch->nextp;
4088 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4090 /* Turn off WATCHED flag in scp */
4091 fid = smb_GetSMBParm(watch, 21);
4092 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
4094 fidp = smb_FindFID(vcp, fid, 0);
4096 osi_Log3(afsd_logp, "Cancelling change notification for fid %d wtree %d file %s",
4098 osi_LogSaveString(afsd_logp, fidp->NTopen_wholepathp));
4101 lock_ObtainMutex(&scp->mx);
4103 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4105 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
4106 lock_ReleaseMutex(&scp->mx);
4107 smb_ReleaseFID(fidp);
4109 /* assume STATUS32; return 0xC0000120 (CANCELED) */
4110 replyWctp = watch->wctp;
4114 ((smb_t *)watch)->rcls = 0x20;
4115 ((smb_t *)watch)->reh = 0x1;
4116 ((smb_t *)watch)->errLow = 0;
4117 ((smb_t *)watch)->errHigh = 0xC0;
4118 ((smb_t *)watch)->flg2 |= 0x4000;
4119 smb_SendPacket(vcp, watch);
4120 smb_FreePacket(watch);
4124 watch = watch->nextp;
4126 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4133 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
4136 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
4141 smb_username_t *unp;
4143 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
4145 lock_ObtainMutex(&unp->mx);
4146 unp->userp = cm_NewUser();
4147 lock_ReleaseMutex(&unp->mx);
4148 #ifdef DEBUG_VERBOSE
4150 HANDLE h; char *ptbuf[1],buf[132];
4151 h = RegisterEventSource(NULL, "AFS Service - smb_FindCMUserByName");
4152 sprintf(buf,"New User name[%s] machine[%s]",usern,machine);
4154 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
4155 DeregisterEventSource(h);
4159 #ifdef DEBUG_VERBOSE
4161 HANDLE h; char *ptbuf[1],buf[132];
4162 h = RegisterEventSource(NULL, "AFS Service - smb_FindCMUserByName");
4163 sprintf(buf,"Found-name[%s] machine[%s]",usern,machine);
4165 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
4166 DeregisterEventSource(h);