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 osi_hyper_t hzero;
32 smb_packet_t *smb_Directory_Watches = NULL;
33 osi_mutex_t smb_Dir_Watch_Lock;
35 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
37 /* protected by the smb_globalLock */
38 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
40 /* retrieve a held reference to a user structure corresponding to an incoming
42 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
47 uidp = smb_FindUID(vcp, inp->uid, 0);
48 if (!uidp) return NULL;
50 lock_ObtainMutex(&uidp->mx);
52 up = uidp->unp->userp;
55 lock_ReleaseMutex(&uidp->mx);
63 * Return extended attributes.
64 * Right now, we aren't using any of the "new" bits, so this looks exactly
65 * like smb_Attributes() (see smb.c).
67 unsigned long smb_ExtAttributes(cm_scache_t *scp)
71 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
72 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
77 * We used to mark a file RO if it was in an RO volume, but that
78 * turns out to be impolitic in NT. See defect 10007.
81 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
83 if ((scp->unixModeBits & 0222) == 0)
84 attrs |= 1; /* Read-only */
87 attrs = 0x80; /* FILE_ATTRIBUTE_NORMAL */
92 int smb_V3IsStarMask(char *maskp)
97 if (tc == '?' || tc == '*') return 1;
101 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
104 /* skip over null-terminated string */
105 *chainpp = inp + strlen(inp) + 1;
110 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
113 char *usern, *pwd, *pwdx;
115 unsigned short newUid;
121 /* Check for bad conns */
122 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
123 return CM_ERROR_REMOTECONN;
125 /* For NT LM 0.12 and up, get capabilities */
126 if (vcp->flags & SMB_VCFLAG_USENT) {
127 caps = smb_GetSMBParm(inp, 11);
129 vcp->flags |= SMB_VCFLAG_STATUS32;
130 /* for now, ignore other capability bits */
134 tp = smb_GetSMBData(inp, NULL);
135 if (vcp->flags & SMB_VCFLAG_USENT)
136 pwdx = smb_ParseString(tp, &tp);
137 pwd = smb_ParseString(tp, &tp);
138 usern = smb_ParseString(tp, &tp);
140 /* On Windows 2000, this function appears to be called more often than
141 it is expected to be called. This resulted in multiple smb_user_t
142 records existing all for the same user session which results in all
143 of the users tokens disappearing.
145 To avoid this problem, we look for an existing smb_user_t record
146 based on the users name, and use that one if we find it.
149 uidp = smb_FindUserByNameThisSession(vcp, usern);
150 if (uidp) { /* already there, so don't create a new one */
153 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
154 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,usern);
155 osi_Log3(afsd_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
156 smb_ReleaseUID(uidp);
159 /* do a global search for the username/machine name pair */
160 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
162 /* Create a new UID and cm_user_t structure */
165 userp = cm_NewUser();
166 lock_ObtainMutex(&vcp->mx);
167 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
168 lock_ReleaseMutex(&vcp->mx);
170 /* Create a new smb_user_t structure and connect them up */
171 lock_ObtainMutex(&unp->mx);
173 lock_ReleaseMutex(&unp->mx);
175 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
176 lock_ObtainMutex(&uidp->mx);
178 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",(int)vcp,vcp->lana,vcp->lsn,newUid,usern);
179 osi_Log4(afsd_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
180 lock_ReleaseMutex(&uidp->mx);
181 smb_ReleaseUID(uidp);
184 /* Return UID to the client */
185 ((smb_t *)outp)->uid = newUid;
186 /* Also to the next chained message */
187 ((smb_t *)inp)->uid = newUid;
189 osi_Log3(afsd_logp, "SMB3 session setup name %s creating ID %d%s",
190 osi_LogSaveString(afsd_logp, usern), newUid, osi_LogSaveString(afsd_logp, s1));
191 smb_SetSMBParm(outp, 2, 0);
192 smb_SetSMBDataLength(outp, 0);
196 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
200 /* don't get tokens from this VC */
201 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
203 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
205 /* find the tree and free it */
206 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
208 char *s1 = NULL, *s2 = NULL;
210 if (s2 == NULL) s2 = " ";
211 if (s1 == NULL) {s1 = s2; s2 = " ";}
213 osi_Log4(afsd_logp, "SMB3 user logoffX uid %d name %s%s%s",
215 osi_LogSaveString(afsd_logp,
216 (uidp->unp) ? uidp->unp->name: " "), s1, s2);
218 lock_ObtainMutex(&uidp->mx);
219 uidp->flags |= SMB_USERFLAG_DELETE;
221 * it doesn't get deleted right away
222 * because the vcp points to it
224 lock_ReleaseMutex(&uidp->mx);
227 osi_Log0(afsd_logp, "SMB3 user logoffX");
229 smb_SetSMBDataLength(outp, 0);
233 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
236 unsigned short newTid;
246 osi_Log0(afsd_logp, "SMB3 receive tree connect");
248 /* parse input parameters */
249 tp = smb_GetSMBData(inp, NULL);
250 passwordp = smb_ParseString(tp, &tp);
251 pathp = smb_ParseString(tp, &tp);
252 servicep = smb_ParseString(tp, &tp);
254 tp = strrchr(pathp, '\\');
256 return CM_ERROR_BADSMB;
258 strcpy(shareName, tp+1);
260 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0)
261 return CM_ERROR_NOIPC;
263 userp = smb_GetUser(vcp, inp);
265 lock_ObtainMutex(&vcp->mx);
266 newTid = vcp->tidCounter++;
267 lock_ReleaseMutex(&vcp->mx);
269 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
270 shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
272 smb_ReleaseTID(tidp);
273 return CM_ERROR_BADSHARENAME;
275 lock_ObtainMutex(&tidp->mx);
277 tidp->pathname = sharePath;
278 lock_ReleaseMutex(&tidp->mx);
279 smb_ReleaseTID(tidp);
281 if (vcp->flags & SMB_VCFLAG_USENT)
282 smb_SetSMBParm(outp, 2, 0); /* OptionalSupport bits */
284 ((smb_t *)outp)->tid = newTid;
285 ((smb_t *)inp)->tid = newTid;
286 tp = smb_GetSMBData(outp, NULL);
290 smb_SetSMBDataLength(outp, 3);
292 osi_Log1(afsd_logp, "SMB3 tree connect created ID %d", newTid);
296 /* must be called with global tran lock held */
297 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
299 smb_tran2Packet_t *tp;
302 smbp = (smb_t *) inp->data;
303 for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
304 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
310 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
311 int totalParms, int totalData)
313 smb_tran2Packet_t *tp;
316 smbp = (smb_t *) inp->data;
317 tp = malloc(sizeof(*tp));
318 memset(tp, 0, sizeof(*tp));
321 tp->curData = tp->curParms = 0;
322 tp->totalData = totalData;
323 tp->totalParms = totalParms;
328 tp->res[0] = smbp->res[0];
329 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
330 tp->opcode = smb_GetSMBParm(inp, 14);
332 tp->parmsp = malloc(totalParms);
334 tp->datap = malloc(totalData);
335 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
339 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
340 smb_tran2Packet_t *inp, smb_packet_t *outp,
341 int totalParms, int totalData)
343 smb_tran2Packet_t *tp;
344 unsigned short parmOffset;
345 unsigned short dataOffset;
346 unsigned short dataAlign;
348 tp = malloc(sizeof(*tp));
349 memset(tp, 0, sizeof(*tp));
351 tp->curData = tp->curParms = 0;
352 tp->totalData = totalData;
353 tp->totalParms = totalParms;
354 tp->oldTotalParms = totalParms;
359 tp->res[0] = inp->res[0];
360 tp->opcode = inp->opcode;
363 * We calculate where the parameters and data will start.
364 * This calculation must parallel the calculation in
365 * smb_SendTran2Packet.
368 parmOffset = 10*2 + 35;
369 parmOffset++; /* round to even */
370 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
372 dataOffset = parmOffset + totalParms;
373 dataAlign = dataOffset & 2; /* quad-align */
374 dataOffset += dataAlign;
375 tp->datap = outp->data + dataOffset;
380 /* free a tran2 packet; must be called with smb_globalLock held */
381 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
383 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
384 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
393 /* called with a VC, an input packet to respond to, and an error code.
394 * sends an error response.
396 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
397 smb_packet_t *tp, long code)
400 unsigned short errCode;
401 unsigned char errClass;
402 unsigned long NTStatus;
404 if (vcp->flags & SMB_VCFLAG_STATUS32)
405 smb_MapNTError(code, &NTStatus);
407 smb_MapCoreError(code, vcp, &errCode, &errClass);
409 smb_FormatResponsePacket(vcp, NULL, tp);
412 /* We can handle long names */
413 if (vcp->flags & SMB_VCFLAG_USENT)
414 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
416 /* now copy important fields from the tran 2 packet */
417 smbp->com = 0x32; /* tran 2 response */
418 smbp->tid = t2p->tid;
419 smbp->mid = t2p->mid;
420 smbp->pid = t2p->pid;
421 smbp->uid = t2p->uid;
422 smbp->res[0] = t2p->res[0];
423 if (vcp->flags & SMB_VCFLAG_STATUS32) {
424 smbp->rcls = (unsigned char) (NTStatus & 0xff);
425 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
426 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
427 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
428 smbp->flg2 |= 0x4000;
431 smbp->rcls = errClass;
432 smbp->errLow = (unsigned char) (errCode & 0xff);
433 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
437 smb_SendPacket(vcp, tp);
440 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
443 unsigned short parmOffset;
444 unsigned short dataOffset;
445 unsigned short totalLength;
446 unsigned short dataAlign;
449 smb_FormatResponsePacket(vcp, NULL, tp);
452 /* We can handle long names */
453 if (vcp->flags & SMB_VCFLAG_USENT)
454 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
456 /* now copy important fields from the tran 2 packet */
457 smbp->com = 0x32; /* tran 2 response */
458 smbp->tid = t2p->tid;
459 smbp->mid = t2p->mid;
460 smbp->pid = t2p->pid;
461 smbp->uid = t2p->uid;
462 smbp->res[0] = t2p->res[0];
464 totalLength = 1 + t2p->totalData + t2p->totalParms;
466 /* now add the core parameters (tran2 info) to the packet */
467 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
468 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
469 smb_SetSMBParm(tp, 2, 0); /* reserved */
470 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
471 parmOffset = 10*2 + 35; /* parm offset in packet */
472 parmOffset++; /* round to even */
473 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
474 * hdr, bcc and wct */
475 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
476 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
477 dataOffset = parmOffset + t2p->oldTotalParms;
478 dataAlign = dataOffset & 2; /* quad-align */
479 dataOffset += dataAlign;
480 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
481 smb_SetSMBParm(tp, 8, 0); /* data displacement */
482 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
485 datap = smb_GetSMBData(tp, NULL);
486 *datap++ = 0; /* we rounded to even */
488 totalLength += dataAlign;
489 smb_SetSMBDataLength(tp, totalLength);
491 /* next, send the datagram */
492 smb_SendPacket(vcp, tp);
495 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
497 smb_tran2Packet_t *asp;
509 /* We sometimes see 0 word count. What to do? */
510 if (*inp->wctp == 0) {
515 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0");
517 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
518 ptbuf[0] = "Transaction2 word count = 0";
519 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
520 1, inp->ncb_length, ptbuf, inp);
521 DeregisterEventSource(h);
523 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0");
526 smb_SetSMBDataLength(outp, 0);
527 smb_SendPacket(vcp, outp);
531 totalParms = smb_GetSMBParm(inp, 0);
532 totalData = smb_GetSMBParm(inp, 1);
534 firstPacket = (inp->inCom == 0x32);
536 /* find the packet we're reassembling */
537 lock_ObtainWrite(&smb_globalLock);
538 asp = smb_FindTran2Packet(vcp, inp);
540 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
542 lock_ReleaseWrite(&smb_globalLock);
544 /* now merge in this latest packet; start by looking up offsets */
546 parmDisp = dataDisp = 0;
547 parmOffset = smb_GetSMBParm(inp, 10);
548 dataOffset = smb_GetSMBParm(inp, 12);
549 parmCount = smb_GetSMBParm(inp, 9);
550 dataCount = smb_GetSMBParm(inp, 11);
551 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
552 asp->maxReturnData = smb_GetSMBParm(inp, 3);
554 osi_Log3(afsd_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
555 totalData, dataCount, asp->maxReturnData);
558 parmDisp = smb_GetSMBParm(inp, 4);
559 parmOffset = smb_GetSMBParm(inp, 3);
560 dataDisp = smb_GetSMBParm(inp, 7);
561 dataOffset = smb_GetSMBParm(inp, 6);
562 parmCount = smb_GetSMBParm(inp, 2);
563 dataCount = smb_GetSMBParm(inp, 5);
565 osi_Log2(afsd_logp, "SMB3 received T2 aux packet parms %d, data %d",
566 parmCount, dataCount);
569 /* now copy the parms and data */
570 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
571 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
573 /* account for new bytes */
574 asp->curData += dataCount;
575 asp->curParms += parmCount;
577 /* finally, if we're done, remove the packet from the queue and dispatch it */
578 if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
579 /* we've received it all */
580 lock_ObtainWrite(&smb_globalLock);
581 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
582 lock_ReleaseWrite(&smb_globalLock);
584 /* now dispatch it */
585 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
586 osi_Log4(afsd_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
587 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
589 /* if an error is returned, we're supposed to send an error packet,
590 * otherwise the dispatched function already did the data sending.
591 * We give dispatched proc the responsibility since it knows how much
595 smb_SendTran2Error(vcp, asp, outp, code);
598 /* free the input tran 2 packet */
599 lock_ObtainWrite(&smb_globalLock);
600 smb_FreeTran2Packet(asp);
601 lock_ReleaseWrite(&smb_globalLock);
603 else if (firstPacket) {
604 /* the first packet in a multi-packet request, we need to send an
605 * ack to get more data.
607 smb_SetSMBDataLength(outp, 0);
608 smb_SendPacket(vcp, outp);
614 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
617 smb_tran2Packet_t *outp;
622 cm_scache_t *dscp; /* dir we're dealing with */
623 cm_scache_t *scp; /* file we're creating */
635 int parmSlot; /* which parm we're dealing with */
644 extraInfo = (p->parmsp[0] & 1); /* return extra info */
645 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
647 openFun = p->parmsp[6]; /* open function */
648 excl = ((openFun & 3) == 0);
649 trunc = ((openFun & 3) == 2); /* truncate it */
650 openMode = (p->parmsp[1] & 0x7);
651 openAction = 0; /* tracks what we did */
653 attributes = p->parmsp[3];
654 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
656 /* compute initial mode bits based on read-only flag in attributes */
657 initialModeBits = 0666;
658 if (attributes & 1) initialModeBits &= ~0222;
660 pathp = (char *) (&p->parmsp[14]);
662 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
664 spacep = cm_GetSpace();
665 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
667 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
668 /* special case magic file name for receiving IOCTL requests
669 * (since IOCTL calls themselves aren't getting through).
671 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
672 smb_SetupIoctlFid(fidp, spacep);
674 /* copy out remainder of the parms */
676 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
678 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
679 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
680 outp->parmsp[parmSlot] = 0; parmSlot++;
681 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
682 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
683 outp->parmsp[parmSlot] = openMode; parmSlot++;
684 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
685 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
687 /* and the final "always present" stuff */
688 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
689 /* next write out the "unique" ID */
690 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
691 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
692 outp->parmsp[parmSlot] = 0; parmSlot++;
693 if (returnEALength) {
694 outp->parmsp[parmSlot] = 0; parmSlot++;
695 outp->parmsp[parmSlot] = 0; parmSlot++;
699 outp->totalParms = parmSlot * 2;
701 smb_SendTran2Packet(vcp, outp, op);
703 smb_FreeTran2Packet(outp);
705 /* and clean up fid reference */
706 smb_ReleaseFID(fidp);
710 userp = smb_GetTran2User(vcp, p);
711 tidPathp = smb_GetTIDPath(vcp, p->tid);
714 code = cm_NameI(cm_rootSCachep, pathp,
715 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
716 userp, tidPathp, &req, &scp);
718 code = cm_NameI(cm_rootSCachep, spacep->data,
719 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
720 userp, tidPathp, &req, &dscp);
721 cm_FreeSpace(spacep);
724 cm_ReleaseUser(userp);
725 smb_FreeTran2Packet(outp);
729 /* otherwise, scp points to the parent directory. Do a lookup,
730 * and truncate the file if we find it, otherwise we create the
733 if (!lastNamep) lastNamep = pathp;
735 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
737 if (code && code != CM_ERROR_NOSUCHFILE) {
738 cm_ReleaseSCache(dscp);
739 cm_ReleaseUser(userp);
740 smb_FreeTran2Packet(outp);
745 cm_FreeSpace(spacep);
748 /* if we get here, if code is 0, the file exists and is represented by
749 * scp. Otherwise, we have to create it.
752 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
754 if (dscp) cm_ReleaseSCache(dscp);
755 cm_ReleaseSCache(scp);
756 cm_ReleaseUser(userp);
757 smb_FreeTran2Packet(outp);
762 /* oops, file shouldn't be there */
763 if (dscp) cm_ReleaseSCache(dscp);
764 cm_ReleaseSCache(scp);
765 cm_ReleaseUser(userp);
766 smb_FreeTran2Packet(outp);
767 return CM_ERROR_EXISTS;
771 setAttr.mask = CM_ATTRMASK_LENGTH;
772 setAttr.length.LowPart = 0;
773 setAttr.length.HighPart = 0;
774 code = cm_SetAttr(scp, &setAttr, userp, &req);
775 openAction = 3; /* truncated existing file */
777 else openAction = 1; /* found existing file */
779 else if (!(openFun & 0x10)) {
780 /* don't create if not found */
781 if (dscp) cm_ReleaseSCache(dscp);
782 osi_assert(scp == NULL);
783 cm_ReleaseUser(userp);
784 smb_FreeTran2Packet(outp);
785 return CM_ERROR_NOSUCHFILE;
788 osi_assert(dscp != NULL && scp == NULL);
789 openAction = 2; /* created file */
790 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
791 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
792 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
794 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
795 smb_NotifyChange(FILE_ACTION_ADDED,
796 FILE_NOTIFY_CHANGE_FILE_NAME,
797 dscp, lastNamep, NULL, TRUE);
798 if (!excl && code == CM_ERROR_EXISTS) {
799 /* not an exclusive create, and someone else tried
800 * creating it already, then we open it anyway. We
801 * don't bother retrying after this, since if this next
802 * fails, that means that the file was deleted after we
805 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
809 setAttr.mask = CM_ATTRMASK_LENGTH;
810 setAttr.length.LowPart = 0;
811 setAttr.length.HighPart = 0;
812 code = cm_SetAttr(scp, &setAttr, userp,
815 } /* lookup succeeded */
819 /* we don't need this any longer */
820 if (dscp) cm_ReleaseSCache(dscp);
823 /* something went wrong creating or truncating the file */
824 if (scp) cm_ReleaseSCache(scp);
825 cm_ReleaseUser(userp);
826 smb_FreeTran2Packet(outp);
830 /* make sure we're about to open a file */
831 if (scp->fileType != CM_SCACHETYPE_FILE) {
832 cm_ReleaseSCache(scp);
833 cm_ReleaseUser(userp);
834 smb_FreeTran2Packet(outp);
835 return CM_ERROR_ISDIR;
838 /* now all we have to do is open the file itself */
839 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
842 /* save a pointer to the vnode */
845 /* compute open mode */
846 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
847 if (openMode == 1 || openMode == 2)
848 fidp->flags |= SMB_FID_OPENWRITE;
850 smb_ReleaseFID(fidp);
852 cm_Open(scp, 0, userp);
854 /* copy out remainder of the parms */
856 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
857 lock_ObtainMutex(&scp->mx);
859 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
860 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
861 outp->parmsp[parmSlot] = dosTime & 0xffff; parmSlot++;
862 outp->parmsp[parmSlot] = (dosTime>>16) & 0xffff; parmSlot++;
863 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
865 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
867 outp->parmsp[parmSlot] = openMode; parmSlot++;
868 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
869 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
871 /* and the final "always present" stuff */
872 outp->parmsp[parmSlot] = openAction; parmSlot++;
873 /* next write out the "unique" ID */
874 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
875 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
876 outp->parmsp[parmSlot] = 0; parmSlot++;
877 if (returnEALength) {
878 outp->parmsp[parmSlot] = 0; parmSlot++;
879 outp->parmsp[parmSlot] = 0; parmSlot++;
881 lock_ReleaseMutex(&scp->mx);
882 outp->totalData = 0; /* total # of data bytes */
883 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
885 smb_SendTran2Packet(vcp, outp, op);
887 smb_FreeTran2Packet(outp);
889 cm_ReleaseUser(userp);
890 /* leave scp held since we put it in fidp->scp */
894 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
896 return CM_ERROR_BADOP;
899 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
901 return CM_ERROR_BADOP;
904 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
906 smb_tran2Packet_t *outp;
907 smb_tran2QFSInfo_t qi;
910 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
912 osi_Log1(afsd_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
914 switch (p->parmsp[0]) {
915 case 1: responseSize = sizeof(qi.u.allocInfo); break;
916 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
917 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
918 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
919 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
920 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
921 default: return CM_ERROR_INVAL;
924 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
925 switch (p->parmsp[0]) {
928 qi.u.allocInfo.FSID = 0;
929 qi.u.allocInfo.sectorsPerAllocUnit = 1;
930 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
931 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
932 qi.u.allocInfo.bytesPerSector = 1024;
937 qi.u.volumeInfo.vsn = 1234;
938 qi.u.volumeInfo.vnCount = 4;
939 /* we're supposed to pad it out with zeroes to the end */
940 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
941 strcpy(qi.u.volumeInfo.label, "AFS");
946 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
947 qi.u.FSvolumeInfo.vsn = 1234;
948 qi.u.FSvolumeInfo.vnCount = 4;
949 strcpy(qi.u.FSvolumeInfo.label, "AFS");
955 temp.LowPart = 0x7fffffff;
956 qi.u.FSsizeInfo.totalAllocUnits = temp;
957 temp.LowPart = 0x3fffffff;
958 qi.u.FSsizeInfo.availAllocUnits = temp;
959 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
960 qi.u.FSsizeInfo.bytesPerSector = 1024;
965 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
966 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
970 /* FS attribute info */
971 /* attributes, defined in WINNT.H:
972 * FILE_CASE_SENSITIVE_SEARCH 0x1
973 * FILE_CASE_PRESERVED_NAMES 0x2
974 * <no name defined> 0x4000
975 * If bit 0x4000 is not set, Windows 95 thinks
976 * we can't handle long (non-8.3) names,
977 * despite our protestations to the contrary.
979 qi.u.FSattributeInfo.attributes = 0x4003;
980 qi.u.FSattributeInfo.maxCompLength = 255;
981 qi.u.FSattributeInfo.FSnameLength = 6;
982 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
986 /* copy out return data, and set corresponding sizes */
987 outp->totalParms = 0;
988 outp->totalData = responseSize;
989 memcpy(outp->datap, &qi, responseSize);
991 /* send and free the packets */
992 smb_SendTran2Packet(vcp, outp, op);
993 smb_FreeTran2Packet(outp);
998 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1000 return CM_ERROR_BADOP;
1003 struct smb_ShortNameRock {
1007 size_t shortNameLen;
1010 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
1013 struct smb_ShortNameRock *rockp;
1017 /* compare both names and vnodes, though probably just comparing vnodes
1018 * would be safe enough.
1020 if (stricmp(dep->name, rockp->maskp) != 0)
1022 if (ntohl(dep->fid.vnode) != rockp->vnode)
1024 /* This is the entry */
1025 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1026 rockp->shortNameLen = shortNameEnd - rockp->shortName;
1027 return CM_ERROR_STOPNOW;
1030 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1031 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1033 struct smb_ShortNameRock rock;
1037 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1041 spacep = cm_GetSpace();
1042 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1044 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1046 cm_FreeSpace(spacep);
1047 if (code) return code;
1049 if (!lastNamep) lastNamep = pathp;
1052 thyper.HighPart = 0;
1053 rock.shortName = shortName;
1055 rock.maskp = lastNamep;
1056 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1059 cm_ReleaseSCache(dscp);
1062 return CM_ERROR_NOSUCHFILE;
1063 if (code == CM_ERROR_STOPNOW) {
1064 *shortNameLenp = rock.shortNameLen;
1070 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1072 smb_tran2Packet_t *outp;
1073 unsigned long dosTime;
1075 unsigned short infoLevel;
1077 unsigned short attributes;
1078 unsigned long extAttributes;
1083 cm_scache_t *scp, *dscp;
1092 infoLevel = p->parmsp[0];
1093 if (infoLevel == 6) nbytesRequired = 0;
1094 else if (infoLevel == 1) nbytesRequired = 22;
1095 else if (infoLevel == 2) nbytesRequired = 26;
1096 else if (infoLevel == 0x101) nbytesRequired = 40;
1097 else if (infoLevel == 0x102) nbytesRequired = 24;
1098 else if (infoLevel == 0x103) nbytesRequired = 4;
1099 else if (infoLevel == 0x108) nbytesRequired = 30;
1101 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1102 p->opcode, infoLevel);
1103 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1106 osi_Log2(afsd_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1107 osi_LogSaveString(afsd_logp, (char *)(&p->parmsp[3])));
1109 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1111 if (infoLevel > 0x100)
1112 outp->totalParms = 2;
1114 outp->totalParms = 0;
1115 outp->totalData = nbytesRequired;
1117 /* now, if we're at infoLevel 6, we're only being asked to check
1118 * the syntax, so we just OK things now. In particular, we're *not*
1119 * being asked to verify anything about the state of any parent dirs.
1121 if (infoLevel == 6) {
1122 smb_SendTran2Packet(vcp, outp, opx);
1123 smb_FreeTran2Packet(outp);
1127 userp = smb_GetTran2User(vcp, p);
1129 tidPathp = smb_GetTIDPath(vcp, p->tid);
1132 * XXX Strange hack XXX
1134 * As of Patch 7 (13 January 98), we are having the following problem:
1135 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1136 * requests to look up "desktop.ini" in all the subdirectories.
1137 * This can cause zillions of timeouts looking up non-existent cells
1138 * and volumes, especially in the top-level directory.
1140 * We have not found any way to avoid this or work around it except
1141 * to explicitly ignore the requests for mount points that haven't
1142 * yet been evaluated and for directories that haven't yet been
1145 if (infoLevel == 0x101) {
1146 spacep = cm_GetSpace();
1147 smb_StripLastComponent(spacep->data, &lastComp,
1148 (char *)(&p->parmsp[3]));
1149 /* Make sure that lastComp is not NULL */
1151 if (strcmp(lastComp, "\\desktop.ini") == 0) {
1152 code = cm_NameI(cm_rootSCachep, spacep->data,
1156 userp, tidPathp, &req, &dscp);
1158 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1159 && !dscp->mountRootFidp)
1160 code = CM_ERROR_NOSUCHFILE;
1161 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1162 cm_buf_t *bp = buf_Find(dscp, &hzero);
1166 code = CM_ERROR_NOSUCHFILE;
1168 cm_ReleaseSCache(dscp);
1170 cm_FreeSpace(spacep);
1171 cm_ReleaseUser(userp);
1172 smb_SendTran2Error(vcp, p, opx, code);
1173 smb_FreeTran2Packet(outp);
1178 cm_FreeSpace(spacep);
1181 /* now do namei and stat, and copy out the info */
1182 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1183 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1186 cm_ReleaseUser(userp);
1187 smb_SendTran2Error(vcp, p, opx, code);
1188 smb_FreeTran2Packet(outp);
1192 lock_ObtainMutex(&scp->mx);
1193 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1194 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1195 if (code) goto done;
1197 /* now we have the status in the cache entry, and everything is locked.
1198 * Marshall the output data.
1201 /* for info level 108, figure out short name */
1202 if (infoLevel == 0x108) {
1203 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1204 tidPathp, scp->fid.vnode, shortName,
1211 *((u_long *)op) = len * 2; op += 4;
1212 mbstowcs((unsigned short *)op, shortName, len);
1217 if (infoLevel == 1 || infoLevel == 2) {
1218 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1219 *((u_long *)op) = dosTime; op += 4; /* creation time */
1220 *((u_long *)op) = dosTime; op += 4; /* access time */
1221 *((u_long *)op) = dosTime; op += 4; /* write time */
1222 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1223 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1224 attributes = smb_Attributes(scp);
1225 *((u_short *)op) = attributes; op += 2; /* attributes */
1227 else if (infoLevel == 0x101) {
1228 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1229 *((FILETIME *)op) = ft; op += 8; /* creation time */
1230 *((FILETIME *)op) = ft; op += 8; /* last access time */
1231 *((FILETIME *)op) = ft; op += 8; /* last write time */
1232 *((FILETIME *)op) = ft; op += 8; /* last change time */
1233 extAttributes = smb_ExtAttributes(scp);
1234 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1235 *((u_long *)op) = 0; op += 4; /* don't know what this is */
1237 else if (infoLevel == 0x102) {
1238 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1239 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1240 *((u_long *)op) = scp->linkCount; op += 4;
1243 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1246 else if (infoLevel == 0x103) {
1247 memset(op, 0, 4); op += 4; /* EA size */
1250 /* now, if we are being asked about extended attrs, return a 0 size */
1251 if (infoLevel == 2) {
1252 *((u_long *)op) = 0; op += 4;
1256 /* send and free the packets */
1258 lock_ReleaseMutex(&scp->mx);
1259 cm_ReleaseSCache(scp);
1260 cm_ReleaseUser(userp);
1261 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1262 else smb_SendTran2Error(vcp, p, opx, code);
1263 smb_FreeTran2Packet(outp);
1268 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1270 return CM_ERROR_BADOP;
1273 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1275 smb_tran2Packet_t *outp;
1277 unsigned long attributes;
1278 unsigned short infoLevel;
1291 fidp = smb_FindFID(vcp, fid, 0);
1294 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
1298 infoLevel = p->parmsp[1];
1299 if (infoLevel == 0x101) nbytesRequired = 40;
1300 else if (infoLevel == 0x102) nbytesRequired = 24;
1301 else if (infoLevel == 0x103) nbytesRequired = 4;
1302 else if (infoLevel == 0x104) nbytesRequired = 6;
1304 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1305 p->opcode, infoLevel);
1306 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1309 osi_Log2(afsd_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1311 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1313 if (infoLevel > 0x100)
1314 outp->totalParms = 2;
1316 outp->totalParms = 0;
1317 outp->totalData = nbytesRequired;
1319 userp = smb_GetTran2User(vcp, p);
1322 lock_ObtainMutex(&scp->mx);
1323 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1324 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1325 if (code) goto done;
1327 /* now we have the status in the cache entry, and everything is locked.
1328 * Marshall the output data.
1331 if (infoLevel == 0x101) {
1332 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1333 *((FILETIME *)op) = ft; op += 8; /* creation time */
1334 *((FILETIME *)op) = ft; op += 8; /* last access time */
1335 *((FILETIME *)op) = ft; op += 8; /* last write time */
1336 *((FILETIME *)op) = ft; op += 8; /* last change time */
1337 attributes = smb_ExtAttributes(scp);
1338 *((u_long *)op) = attributes; op += 4;
1339 *((u_long *)op) = 0; op += 4;
1341 else if (infoLevel == 0x102) {
1342 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1343 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1344 *((u_long *)op) = scp->linkCount; op += 4;
1345 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1346 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1350 else if (infoLevel == 0x103) {
1351 *((u_long *)op) = 0; op += 4;
1353 else if (infoLevel == 0x104) {
1357 if (fidp->NTopen_wholepathp)
1358 name = fidp->NTopen_wholepathp;
1360 name = "\\"; /* probably can't happen */
1362 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
1363 *((u_long *)op) = len * 2; op += 4;
1364 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1367 /* send and free the packets */
1369 lock_ReleaseMutex(&scp->mx);
1370 cm_ReleaseUser(userp);
1371 smb_ReleaseFID(fidp);
1372 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1373 else smb_SendTran2Error(vcp, p, opx, code);
1374 smb_FreeTran2Packet(outp);
1379 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1384 unsigned short infoLevel;
1385 smb_tran2Packet_t *outp;
1393 fidp = smb_FindFID(vcp, fid, 0);
1396 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1400 infoLevel = p->parmsp[1];
1401 if (infoLevel > 0x104 || infoLevel < 0x101) {
1402 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1403 p->opcode, infoLevel);
1404 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1408 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1409 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1412 if ((infoLevel == 0x103 || infoLevel == 0x104)
1413 && !(fidp->flags & SMB_FID_OPENWRITE)) {
1414 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1418 osi_Log1(afsd_logp, "T2 SFileInfo type 0x%x", infoLevel);
1420 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1422 outp->totalParms = 2;
1423 outp->totalData = 0;
1425 userp = smb_GetTran2User(vcp, p);
1429 if (infoLevel == 0x101) {
1431 unsigned int attribute;
1434 /* lock the vnode with a callback; we need the current status
1435 * to determine what the new status is, in some cases.
1437 lock_ObtainMutex(&scp->mx);
1438 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1439 CM_SCACHESYNC_GETSTATUS
1440 | CM_SCACHESYNC_NEEDCALLBACK);
1442 lock_ReleaseMutex(&scp->mx);
1446 /* prepare for setattr call */
1449 lastMod = *((FILETIME *)(p->datap + 16));
1450 /* when called as result of move a b, lastMod is (-1, -1). If the check for -1 is not present, timestamp
1451 of the resulting file will be 1969 (-1)
1453 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
1454 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1455 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1457 fidp->flags |= SMB_FID_MTIMESETDONE;
1460 attribute = *((u_long *)(p->datap + 32));
1461 if (attribute != 0) {
1462 if ((scp->unixModeBits & 0222)
1463 && (attribute & 1) != 0) {
1464 /* make a writable file read-only */
1465 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1466 attr.unixModeBits = scp->unixModeBits & ~0222;
1468 else if ((scp->unixModeBits & 0222) == 0
1469 && (attribute & 1) == 0) {
1470 /* make a read-only file writable */
1471 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1472 attr.unixModeBits = scp->unixModeBits | 0222;
1475 lock_ReleaseMutex(&scp->mx);
1479 code = cm_SetAttr(scp, &attr, userp, &req);
1483 else if (infoLevel == 0x103 || infoLevel == 0x104) {
1484 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1487 attr.mask = CM_ATTRMASK_LENGTH;
1488 attr.length.LowPart = size.LowPart;
1489 attr.length.HighPart = size.HighPart;
1490 code = cm_SetAttr(scp, &attr, userp, &req);
1492 else if (infoLevel == 0x102) {
1493 if (*((char *)(p->datap))) {
1494 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1497 fidp->flags |= SMB_FID_DELONCLOSE;
1501 fidp->flags &= ~SMB_FID_DELONCLOSE;
1505 cm_ReleaseUser(userp);
1506 smb_ReleaseFID(fidp);
1507 if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1508 else smb_SendTran2Error(vcp, p, op, code);
1509 smb_FreeTran2Packet(outp);
1514 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1516 return CM_ERROR_BADOP;
1519 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1521 return CM_ERROR_BADOP;
1524 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1526 return CM_ERROR_BADOP;
1529 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1531 return CM_ERROR_BADOP;
1534 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1536 return CM_ERROR_BADOP;
1539 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1540 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1545 cm_scache_t *targetScp; /* target if scp is a symlink */
1550 unsigned short attr;
1551 unsigned long lattr;
1552 smb_dirListPatch_t *patchp;
1553 smb_dirListPatch_t *npatchp;
1555 for(patchp = *dirPatchespp; patchp; patchp =
1556 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1557 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1559 lock_ObtainMutex(&scp->mx);
1560 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1561 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1563 lock_ReleaseMutex(&scp->mx);
1564 cm_ReleaseSCache(scp);
1568 /* now watch for a symlink */
1569 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1570 lock_ReleaseMutex(&scp->mx);
1571 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp,
1574 /* we have a more accurate file to use (the
1575 * target of the symbolic link). Otherwise,
1576 * we'll just use the symlink anyway.
1578 osi_Log2(afsd_logp, "symlink vp %x to vp %x",
1580 cm_ReleaseSCache(scp);
1583 lock_ObtainMutex(&scp->mx);
1586 dptr = patchp->dptr;
1588 if (infoLevel >= 0x101) {
1590 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1592 /* copy to Creation Time */
1593 *((FILETIME *)dptr) = ft;
1596 /* copy to Last Access Time */
1597 *((FILETIME *)dptr) = ft;
1600 /* copy to Last Write Time */
1601 *((FILETIME *)dptr) = ft;
1604 /* copy to Change Time */
1605 *((FILETIME *)dptr) = ft;
1608 /* Use length for both file length and alloc length */
1609 *((LARGE_INTEGER *)dptr) = scp->length;
1611 *((LARGE_INTEGER *)dptr) = scp->length;
1614 /* Copy attributes */
1615 lattr = smb_ExtAttributes(scp);
1616 *((u_long *)dptr) = lattr;
1621 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1623 /* and copy out date */
1624 shortTemp = (dosTime>>16) & 0xffff;
1625 *((u_short *)dptr) = shortTemp;
1628 /* copy out creation time */
1629 shortTemp = dosTime & 0xffff;
1630 *((u_short *)dptr) = shortTemp;
1633 /* and copy out date */
1634 shortTemp = (dosTime>>16) & 0xffff;
1635 *((u_short *)dptr) = shortTemp;
1638 /* copy out access time */
1639 shortTemp = dosTime & 0xffff;
1640 *((u_short *)dptr) = shortTemp;
1643 /* and copy out date */
1644 shortTemp = (dosTime>>16) & 0xffff;
1645 *((u_short *)dptr) = shortTemp;
1648 /* copy out mod time */
1649 shortTemp = dosTime & 0xffff;
1650 *((u_short *)dptr) = shortTemp;
1653 /* copy out file length and alloc length,
1654 * using the same for both
1656 *((u_long *)dptr) = scp->length.LowPart;
1658 *((u_long *)dptr) = scp->length.LowPart;
1661 /* finally copy out attributes as short */
1662 attr = smb_Attributes(scp);
1663 *dptr++ = attr & 0xff;
1664 *dptr++ = (attr >> 8) & 0xff;
1667 lock_ReleaseMutex(&scp->mx);
1668 cm_ReleaseSCache(scp);
1671 /* now free the patches */
1672 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1673 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1677 /* and mark the list as empty */
1678 *dirPatchespp = NULL;
1683 /* do a case-folding search of the star name mask with the name in namep.
1684 * Return 1 if we match, otherwise 0.
1686 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1688 unsigned char tcp1, tcp2; /* Pattern characters */
1689 unsigned char tcn1; /* Name characters */
1690 int sawDot = 0, sawStar = 0;
1691 char *starNamep, *starMaskp;
1692 static char nullCharp[] = {0};
1694 /* make sure we only match 8.3 names, if requested */
1695 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) return 0;
1699 /* Next pattern character */
1702 /* Next name character */
1706 /* 0 - end of pattern */
1712 else if (tcp1 == '.' || tcp1 == '"') {
1722 * first dot in pattern;
1723 * must match dot or end of name
1728 else if (tcn1 == '.') {
1737 else if (tcp1 == '?') {
1738 if (tcn1 == 0 || tcn1 == '.')
1743 else if (tcp1 == '>') {
1744 if (tcn1 != 0 && tcn1 != '.')
1748 else if (tcp1 == '*' || tcp1 == '<') {
1752 else if (tcp2 == '.' || tcp2 == '"') {
1753 while (tcn1 != '.' && tcn1 != 0)
1768 * pattern character after '*' is not null or
1769 * period. If it is '?' or '>', we are not
1770 * going to understand it. If it is '*' or
1771 * '<', we are going to skip over it. None of
1772 * these are likely, I hope.
1774 /* skip over '*' and '<' */
1775 while (tcp2 == '*' || tcp2 == '<')
1778 /* skip over characters that don't match tcp2 */
1779 while (tcn1 != '.' && tcn1 != 0
1780 && cm_foldUpper[tcn1] != cm_foldUpper[tcp2])
1784 if (tcn1 == '.' || tcn1 == 0)
1787 /* Remember where we are */
1797 /* tcp1 is not a wildcard */
1798 if (cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) {
1803 /* if trying to match a star pattern, go back */
1805 maskp = starMaskp - 2;
1806 namep = starNamep + 1;
1816 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1825 smb_dirListPatch_t *dirListPatchesp;
1826 smb_dirListPatch_t *curPatchp;
1829 long orbytes; /* # of bytes in this output record */
1830 long ohbytes; /* # of bytes, except file name */
1831 long onbytes; /* # of bytes in name, incl. term. null */
1832 osi_hyper_t dirLength;
1833 osi_hyper_t bufferOffset;
1834 osi_hyper_t curOffset;
1836 smb_dirSearch_t *dsp;
1840 cm_pageHeader_t *pageHeaderp;
1841 cm_user_t *userp = NULL;
1844 long nextEntryCookie;
1845 int numDirChunks; /* # of 32 byte dir chunks in this entry */
1846 char *op; /* output data ptr */
1847 char *origOp; /* original value of op */
1848 cm_space_t *spacep; /* for pathname buffer */
1849 long maxReturnData; /* max # of return data */
1850 long maxReturnParms; /* max # of return parms */
1851 long bytesInBuffer; /* # data bytes in the output buffer */
1853 char *maskp; /* mask part of path */
1857 smb_tran2Packet_t *outp; /* response packet */
1860 char shortName[13]; /* 8.3 name if needed */
1871 if (p->opcode == 1) {
1872 /* find first; obtain basic parameters from request */
1873 attribute = p->parmsp[0];
1874 maxCount = p->parmsp[1];
1875 infoLevel = p->parmsp[3];
1876 searchFlags = p->parmsp[2];
1877 dsp = smb_NewDirSearch(1);
1878 dsp->attribute = attribute;
1879 pathp = ((char *) p->parmsp) + 12; /* points to path */
1881 maskp = strrchr(pathp, '\\');
1882 if (maskp == NULL) maskp = pathp;
1883 else maskp++; /* skip over backslash */
1884 strcpy(dsp->mask, maskp); /* and save mask */
1885 /* track if this is likely to match a lot of entries */
1886 starPattern = smb_V3IsStarMask(maskp);
1889 osi_assert(p->opcode == 2);
1890 /* find next; obtain basic parameters from request or open dir file */
1891 dsp = smb_FindDirSearch(p->parmsp[0]);
1892 if (!dsp) return CM_ERROR_BADFD;
1893 attribute = dsp->attribute;
1894 maxCount = p->parmsp[1];
1895 infoLevel = p->parmsp[2];
1896 searchFlags = p->parmsp[5];
1898 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
1900 starPattern = 1; /* assume, since required a Find Next */
1904 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
1905 attribute, infoLevel, maxCount, searchFlags);
1907 osi_Log2(afsd_logp, "...T2 search op %d, nextCookie 0x%x",
1908 p->opcode, nextCookie);
1910 if (infoLevel >= 0x101)
1911 searchFlags &= ~4; /* no resume keys */
1913 dirListPatchesp = NULL;
1915 maxReturnData = p->maxReturnData;
1916 if (p->opcode == 1) /* find first */
1917 maxReturnParms = 10; /* bytes */
1919 maxReturnParms = 8; /* bytes */
1921 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
1922 if (maxReturnData > 6000) maxReturnData = 6000;
1923 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
1925 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
1928 osi_Log1(afsd_logp, "T2 receive search dir %s",
1929 osi_LogSaveString(afsd_logp, pathp));
1931 /* bail out if request looks bad */
1932 if (p->opcode == 1 && !pathp) {
1933 return CM_ERROR_BADSMB;
1936 osi_Log2(afsd_logp, "T2 dir search cookie 0x%x, connection %d",
1937 nextCookie, dsp->cookie);
1939 userp = smb_GetTran2User(vcp, p);
1941 /* try to get the vnode for the path name next */
1942 lock_ObtainMutex(&dsp->mx);
1949 spacep = cm_GetSpace();
1950 smb_StripLastComponent(spacep->data, NULL, pathp);
1951 lock_ReleaseMutex(&dsp->mx);
1953 tidPathp = smb_GetTIDPath(vcp, p->tid);
1954 code = cm_NameI(cm_rootSCachep, spacep->data,
1955 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
1956 userp, tidPathp, &req, &scp);
1957 cm_FreeSpace(spacep);
1959 lock_ObtainMutex(&dsp->mx);
1961 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
1963 /* we need one hold for the entry we just stored into,
1964 * and one for our own processing. When we're done
1965 * with this function, we'll drop the one for our own
1966 * processing. We held it once from the namei call,
1967 * and so we do another hold now.
1970 lock_ObtainMutex(&scp->mx);
1971 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
1972 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
1973 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
1974 dsp->flags |= SMB_DIRSEARCH_BULKST;
1976 lock_ReleaseMutex(&scp->mx);
1979 lock_ReleaseMutex(&dsp->mx);
1981 cm_ReleaseUser(userp);
1982 smb_FreeTran2Packet(outp);
1983 smb_DeleteDirSearch(dsp);
1984 smb_ReleaseDirSearch(dsp);
1988 /* get the directory size */
1989 lock_ObtainMutex(&scp->mx);
1990 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1991 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1993 lock_ReleaseMutex(&scp->mx);
1994 cm_ReleaseSCache(scp);
1995 cm_ReleaseUser(userp);
1996 smb_FreeTran2Packet(outp);
1997 smb_DeleteDirSearch(dsp);
1998 smb_ReleaseDirSearch(dsp);
2002 dirLength = scp->length;
2004 bufferOffset.LowPart = bufferOffset.HighPart = 0;
2005 curOffset.HighPart = 0;
2006 curOffset.LowPart = nextCookie;
2007 origOp = outp->datap;
2014 if (searchFlags & 4)
2015 /* skip over resume key */
2018 /* make sure that curOffset.LowPart doesn't point to the first
2019 * 32 bytes in the 2nd through last dir page, and that it doesn't
2020 * point at the first 13 32-byte chunks in the first dir page,
2021 * since those are dir and page headers, and don't contain useful
2024 temp = curOffset.LowPart & (2048-1);
2025 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2026 /* we're in the first page */
2027 if (temp < 13*32) temp = 13*32;
2030 /* we're in a later dir page */
2031 if (temp < 32) temp = 32;
2034 /* make sure the low order 5 bits are zero */
2037 /* now put temp bits back ito curOffset.LowPart */
2038 curOffset.LowPart &= ~(2048-1);
2039 curOffset.LowPart |= temp;
2041 /* check if we've returned all the names that will fit in the
2042 * response packet; we check return count as well as the number
2043 * of bytes requested. We check the # of bytes after we find
2044 * the dir entry, since we'll need to check its size.
2046 if (returnedNames >= maxCount) break;
2048 /* check if we've passed the dir's EOF */
2049 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2054 /* see if we can use the bufferp we have now; compute in which
2055 * page the current offset would be, and check whether that's
2056 * the offset of the buffer we have. If not, get the buffer.
2058 thyper.HighPart = curOffset.HighPart;
2059 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2060 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2063 buf_Release(bufferp);
2066 lock_ReleaseMutex(&scp->mx);
2067 lock_ObtainRead(&scp->bufCreateLock);
2068 code = buf_Get(scp, &thyper, &bufferp);
2069 lock_ReleaseRead(&scp->bufCreateLock);
2071 /* now, if we're doing a star match, do bulk fetching
2072 * of all of the status info for files in the dir.
2075 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2078 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2079 && LargeIntegerGreaterThanOrEqualTo(
2080 thyper, scp->bulkStatProgress)) {
2081 /* Don't bulk stat if risking timeout */
2082 int now = GetCurrentTime();
2083 if (now - req.startTime > 5000) {
2084 scp->bulkStatProgress = thyper;
2085 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2086 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2088 cm_TryBulkStat(scp, &thyper,
2093 lock_ObtainMutex(&scp->mx);
2095 bufferOffset = thyper;
2097 /* now get the data in the cache */
2099 code = cm_SyncOp(scp, bufferp, userp, &req,
2101 CM_SCACHESYNC_NEEDCALLBACK
2102 | CM_SCACHESYNC_READ);
2105 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2107 /* otherwise, load the buffer and try again */
2108 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2113 buf_Release(bufferp);
2117 } /* if (wrong buffer) ... */
2119 /* now we have the buffer containing the entry we're interested
2120 * in; copy it out if it represents a non-deleted entry.
2122 entryInDir = curOffset.LowPart & (2048-1);
2123 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2125 /* page header will help tell us which entries are free. Page
2126 * header can change more often than once per buffer, since
2127 * AFS 3 dir page size may be less than (but not more than)
2128 * a buffer package buffer.
2130 /* only look intra-buffer */
2131 temp = curOffset.LowPart & (buf_bufferSize - 1);
2132 temp &= ~(2048 - 1); /* turn off intra-page bits */
2133 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2135 /* now determine which entry we're looking at in the page.
2136 * If it is free (there's a free bitmap at the start of the
2137 * dir), we should skip these 32 bytes.
2139 slotInPage = (entryInDir & 0x7e0) >> 5;
2140 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2141 & (1 << (slotInPage & 0x7)))) {
2142 /* this entry is free */
2143 numDirChunks = 1; /* only skip this guy */
2147 tp = bufferp->datap + entryInBuffer;
2148 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
2150 /* while we're here, compute the next entry's location, too,
2151 * since we'll need it when writing out the cookie into the dir
2154 * XXXX Probably should do more sanity checking.
2156 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2158 /* compute offset of cookie representing next entry */
2159 nextEntryCookie = curOffset.LowPart
2160 + (CM_DIR_CHUNKSIZE * numDirChunks);
2162 /* Need 8.3 name? */
2164 if (infoLevel == 0x104
2165 && dep->fid.vnode != 0
2166 && !cm_Is8Dot3(dep->name)) {
2167 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2171 if (dep->fid.vnode != 0
2172 && (smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)
2174 && smb_V3MatchMask(shortName, maskp,
2175 CM_FLAG_CASEFOLD)))) {
2177 /* Eliminate entries that don't match requested
2179 if (!(dsp->attribute & 0x10)) /* no directories */
2181 /* We have already done the cm_TryBulkStat above */
2182 fid.cell = scp->fid.cell;
2183 fid.volume = scp->fid.volume;
2184 fid.vnode = ntohl(dep->fid.vnode);
2185 fid.unique = ntohl(dep->fid.unique);
2186 fileType = cm_FindFileType(&fid);
2187 /*osi_Log2(afsd_logp, "smb_ReceiveTran2SearchDir: file %s "
2188 "has filetype %d", dep->name,
2190 if (fileType == CM_SCACHETYPE_DIRECTORY)
2194 /* finally check if this name will fit */
2196 /* standard dir entry stuff */
2197 if (infoLevel < 0x101)
2198 ohbytes = 23; /* pre-NT */
2199 else if (infoLevel == 0x103)
2200 ohbytes = 12; /* NT names only */
2202 ohbytes = 64; /* NT */
2204 if (infoLevel == 0x104)
2205 ohbytes += 26; /* Short name & length */
2207 if (searchFlags & 4) {
2208 ohbytes += 4; /* if resume key required */
2212 && infoLevel != 0x101
2213 && infoLevel != 0x103)
2214 ohbytes += 4; /* EASIZE */
2216 /* add header to name & term. null */
2217 orbytes = onbytes + ohbytes + 1;
2219 /* now, we round up the record to a 4 byte alignment,
2220 * and we make sure that we have enough room here for
2221 * even the aligned version (so we don't have to worry
2222 * about an * overflow when we pad things out below).
2223 * That's the reason for the alignment arithmetic below.
2225 if (infoLevel >= 0x101)
2226 align = (4 - (orbytes & 3)) & 3;
2229 if (orbytes + bytesInBuffer + align > maxReturnData)
2232 /* this is one of the entries to use: it is not deleted
2233 * and it matches the star pattern we're looking for.
2234 * Put out the name, preceded by its length.
2236 /* First zero everything else */
2237 memset(origOp, 0, ohbytes);
2239 if (infoLevel <= 0x101)
2240 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2241 else if (infoLevel == 0x103)
2242 *((u_long *)(op + 8)) = onbytes;
2244 *((u_long *)(op + 60)) = onbytes;
2245 strcpy(origOp+ohbytes, dep->name);
2247 /* Short name if requested and needed */
2248 if (infoLevel == 0x104) {
2249 if (NeedShortName) {
2250 strcpy(op + 70, shortName);
2251 *(op + 68) = shortNameEnd - shortName;
2255 /* now, adjust the # of entries copied */
2258 /* NextEntryOffset and FileIndex */
2259 if (infoLevel >= 101) {
2260 int entryOffset = orbytes + align;
2261 *((u_long *)op) = entryOffset;
2262 *((u_long *)(op+4)) = nextEntryCookie;
2265 /* now we emit the attribute. This is tricky, since
2266 * we need to really stat the file to find out what
2267 * type of entry we've got. Right now, we're copying
2268 * out data from * a buffer, while holding the scp
2269 * locked, so it isn't really convenient to stat
2270 * something now. We'll put in a place holder
2271 * now, and make a second pass before returning this
2272 * to get the real attributes. So, we just skip the
2273 * data for now, and adjust it later. We allocate a
2274 * patch record to make it easy to find this point
2275 * later. The replay will happen at a time when it is
2276 * safe to unlock the directory.
2278 if (infoLevel != 0x103) {
2279 curPatchp = malloc(sizeof(*curPatchp));
2280 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2282 curPatchp->dptr = op;
2283 if (infoLevel >= 0x101)
2284 curPatchp->dptr += 8;
2285 curPatchp->fid.cell = scp->fid.cell;
2286 curPatchp->fid.volume = scp->fid.volume;
2287 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2288 curPatchp->fid.unique = ntohl(dep->fid.unique);
2291 curPatchp->dep = dep;
2294 if (searchFlags & 4)
2295 /* put out resume key */
2296 *((u_long *)origOp) = nextEntryCookie;
2298 /* Adjust byte ptr and count */
2299 origOp += orbytes; /* skip entire record */
2300 bytesInBuffer += orbytes;
2302 /* and pad the record out */
2303 while (--align >= 0) {
2308 } /* if we're including this name */
2311 /* and adjust curOffset to be where the new cookie is */
2312 thyper.HighPart = 0;
2313 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2314 curOffset = LargeIntegerAdd(thyper, curOffset);
2315 } /* while copying data for dir listing */
2317 /* release the mutex */
2318 lock_ReleaseMutex(&scp->mx);
2319 if (bufferp) buf_Release(bufferp);
2321 /* apply and free last set of patches; if not doing a star match, this
2322 * will be empty, but better safe (and freeing everything) than sorry.
2324 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2327 /* now put out the final parameters */
2328 if (returnedNames == 0) eos = 1;
2329 if (p->opcode == 1) {
2331 outp->parmsp[0] = (unsigned short) dsp->cookie;
2332 outp->parmsp[1] = returnedNames;
2333 outp->parmsp[2] = eos;
2334 outp->parmsp[3] = 0; /* nothing wrong with EAS */
2335 outp->parmsp[4] = 0; /* don't need last name to continue
2336 * search, cookie is enough. Normally,
2337 * this is the offset of the file name
2338 * of the last entry returned.
2340 outp->totalParms = 10; /* in bytes */
2344 outp->parmsp[0] = returnedNames;
2345 outp->parmsp[1] = eos;
2346 outp->parmsp[2] = 0; /* EAS error */
2347 outp->parmsp[3] = 0; /* last name, as above */
2348 outp->totalParms = 8; /* in bytes */
2351 /* return # of bytes in the buffer */
2352 outp->totalData = bytesInBuffer;
2354 osi_Log2(afsd_logp, "T2 search dir done, %d names, code %d",
2355 returnedNames, code);
2357 /* Return error code if unsuccessful on first request */
2358 if (code == 0 && p->opcode == 1 && returnedNames == 0)
2359 code = CM_ERROR_NOSUCHFILE;
2361 /* if we're supposed to close the search after this request, or if
2362 * we're supposed to close the search if we're done, and we're done,
2363 * or if something went wrong, close the search.
2365 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2366 if ((searchFlags & 1) || (returnedNames == 0) || ((searchFlags & 2) &&
2368 smb_DeleteDirSearch(dsp);
2370 smb_SendTran2Error(vcp, p, opx, code);
2372 smb_SendTran2Packet(vcp, outp, opx);
2374 smb_FreeTran2Packet(outp);
2375 smb_ReleaseDirSearch(dsp);
2376 cm_ReleaseSCache(scp);
2377 cm_ReleaseUser(userp);
2381 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2384 smb_dirSearch_t *dsp;
2386 dirHandle = smb_GetSMBParm(inp, 0);
2388 osi_Log1(afsd_logp, "SMB3 find close handle %d", dirHandle);
2390 dsp = smb_FindDirSearch(dirHandle);
2393 return CM_ERROR_BADFD;
2395 /* otherwise, we have an FD to destroy */
2396 smb_DeleteDirSearch(dsp);
2397 smb_ReleaseDirSearch(dsp);
2399 /* and return results */
2400 smb_SetSMBDataLength(outp, 0);
2405 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2407 smb_SetSMBDataLength(outp, 0);
2411 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2418 cm_scache_t *dscp; /* dir we're dealing with */
2419 cm_scache_t *scp; /* file we're creating */
2421 int initialModeBits;
2431 int parmSlot; /* which parm we're dealing with */
2439 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
2440 openFun = smb_GetSMBParm(inp, 8); /* open function */
2441 excl = ((openFun & 3) == 0);
2442 trunc = ((openFun & 3) == 2); /* truncate it */
2443 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2444 openAction = 0; /* tracks what we did */
2446 attributes = smb_GetSMBParm(inp, 5);
2447 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2449 /* compute initial mode bits based on read-only flag in attributes */
2450 initialModeBits = 0666;
2451 if (attributes & 1) initialModeBits &= ~0222;
2453 pathp = smb_GetSMBData(inp, NULL);
2455 spacep = inp->spacep;
2456 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2458 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2459 /* special case magic file name for receiving IOCTL requests
2460 * (since IOCTL calls themselves aren't getting through).
2462 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2463 smb_SetupIoctlFid(fidp, spacep);
2465 /* set inp->fid so that later read calls in same msg can find fid */
2466 inp->fid = fidp->fid;
2468 /* copy out remainder of the parms */
2470 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2472 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2473 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
2474 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2475 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
2476 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2477 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2478 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2479 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2481 /* and the final "always present" stuff */
2482 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2483 /* next write out the "unique" ID */
2484 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2485 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2486 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2487 smb_SetSMBDataLength(outp, 0);
2489 /* and clean up fid reference */
2490 smb_ReleaseFID(fidp);
2494 userp = smb_GetUser(vcp, inp);
2497 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2498 code = cm_NameI(cm_rootSCachep, pathp,
2499 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2500 userp, tidPathp, &req, &scp);
2502 code = cm_NameI(cm_rootSCachep, spacep->data,
2503 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2504 userp, tidPathp, &req, &dscp);
2507 cm_ReleaseUser(userp);
2511 /* otherwise, scp points to the parent directory. Do a lookup,
2512 * and truncate the file if we find it, otherwise we create the
2515 if (!lastNamep) lastNamep = pathp;
2517 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2519 if (code && code != CM_ERROR_NOSUCHFILE) {
2520 cm_ReleaseSCache(dscp);
2521 cm_ReleaseUser(userp);
2526 /* if we get here, if code is 0, the file exists and is represented by
2527 * scp. Otherwise, we have to create it. The dir may be represented
2528 * by dscp, or we may have found the file directly. If code is non-zero,
2532 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2534 if (dscp) cm_ReleaseSCache(dscp);
2535 cm_ReleaseSCache(scp);
2536 cm_ReleaseUser(userp);
2541 /* oops, file shouldn't be there */
2542 if (dscp) cm_ReleaseSCache(dscp);
2543 cm_ReleaseSCache(scp);
2544 cm_ReleaseUser(userp);
2545 return CM_ERROR_EXISTS;
2549 setAttr.mask = CM_ATTRMASK_LENGTH;
2550 setAttr.length.LowPart = 0;
2551 setAttr.length.HighPart = 0;
2552 code = cm_SetAttr(scp, &setAttr, userp, &req);
2553 openAction = 3; /* truncated existing file */
2555 else openAction = 1; /* found existing file */
2557 else if (!(openFun & 0x10)) {
2558 /* don't create if not found */
2559 if (dscp) cm_ReleaseSCache(dscp);
2560 cm_ReleaseUser(userp);
2561 return CM_ERROR_NOSUCHFILE;
2564 osi_assert(dscp != NULL);
2565 osi_Log1(afsd_logp, "smb_ReceiveV3OpenX creating file %s",
2566 osi_LogSaveString(afsd_logp, lastNamep));
2567 openAction = 2; /* created file */
2568 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2569 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2570 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2572 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2573 smb_NotifyChange(FILE_ACTION_ADDED,
2574 FILE_NOTIFY_CHANGE_FILE_NAME,
2575 dscp, lastNamep, NULL, TRUE);
2576 if (!excl && code == CM_ERROR_EXISTS) {
2577 /* not an exclusive create, and someone else tried
2578 * creating it already, then we open it anyway. We
2579 * don't bother retrying after this, since if this next
2580 * fails, that means that the file was deleted after we
2581 * started this call.
2583 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2587 setAttr.mask = CM_ATTRMASK_LENGTH;
2588 setAttr.length.LowPart = 0;
2589 setAttr.length.HighPart = 0;
2590 code = cm_SetAttr(scp, &setAttr, userp,
2593 } /* lookup succeeded */
2597 /* we don't need this any longer */
2598 if (dscp) cm_ReleaseSCache(dscp);
2601 /* something went wrong creating or truncating the file */
2602 if (scp) cm_ReleaseSCache(scp);
2603 cm_ReleaseUser(userp);
2607 /* make sure we're about to open a file */
2608 if (scp->fileType != CM_SCACHETYPE_FILE) {
2609 cm_ReleaseSCache(scp);
2610 cm_ReleaseUser(userp);
2611 return CM_ERROR_ISDIR;
2614 /* now all we have to do is open the file itself */
2615 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2618 /* save a pointer to the vnode */
2621 /* compute open mode */
2622 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2623 if (openMode == 1 || openMode == 2)
2624 fidp->flags |= SMB_FID_OPENWRITE;
2626 smb_ReleaseFID(fidp);
2628 cm_Open(scp, 0, userp);
2630 /* set inp->fid so that later read calls in same msg can find fid */
2631 inp->fid = fidp->fid;
2633 /* copy out remainder of the parms */
2635 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2636 lock_ObtainMutex(&scp->mx);
2638 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2639 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2640 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2641 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2642 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2643 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2644 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2645 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2646 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2648 /* and the final "always present" stuff */
2649 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2650 /* next write out the "unique" ID */
2651 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2652 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2653 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2654 lock_ReleaseMutex(&scp->mx);
2655 smb_SetSMBDataLength(outp, 0);
2657 osi_Log1(afsd_logp, "SMB OpenX opening fid %d", fidp->fid);
2659 cm_ReleaseUser(userp);
2660 /* leave scp held since we put it in fidp->scp */
2664 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2671 unsigned char LockType;
2672 unsigned short NumberOfUnlocks, NumberOfLocks;
2673 unsigned long Timeout;
2675 LARGE_INTEGER LOffset, LLength;
2676 smb_waitingLock_t *waitingLock;
2683 fid = smb_GetSMBParm(inp, 2);
2684 fid = smb_ChainFID(fid, inp);
2686 fidp = smb_FindFID(vcp, fid, 0);
2687 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2688 return CM_ERROR_BADFD;
2690 /* set inp->fid so that later read calls in same msg can find fid */
2693 userp = smb_GetUser(vcp, inp);
2697 lock_ObtainMutex(&scp->mx);
2698 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2699 CM_SCACHESYNC_NEEDCALLBACK
2700 | CM_SCACHESYNC_GETSTATUS
2701 | CM_SCACHESYNC_LOCK);
2702 if (code) goto doneSync;
2704 LockType = smb_GetSMBParm(inp, 3) & 0xff;
2705 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2706 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2707 NumberOfLocks = smb_GetSMBParm(inp, 7);
2709 op = smb_GetSMBData(inp, NULL);
2711 for (i=0; i<NumberOfUnlocks; i++) {
2712 if (LockType & 0x10) {
2714 LOffset.HighPart = *((LONG *)(op + 4));
2715 LOffset.LowPart = *((DWORD *)(op + 8));
2716 LLength.HighPart = *((LONG *)(op + 12));
2717 LLength.LowPart = *((DWORD *)(op + 16));
2721 /* Not Large Files */
2722 LOffset.HighPart = 0;
2723 LOffset.LowPart = *((DWORD *)(op + 2));
2724 LLength.HighPart = 0;
2725 LLength.LowPart = *((DWORD *)(op + 6));
2728 if (LargeIntegerNotEqualToZero(LOffset))
2730 /* Do not check length -- length check done in cm_Unlock */
2732 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2733 if (code) goto done;
2736 for (i=0; i<NumberOfLocks; i++) {
2737 if (LockType & 0x10) {
2739 LOffset.HighPart = *((LONG *)(op + 4));
2740 LOffset.LowPart = *((DWORD *)(op + 8));
2741 LLength.HighPart = *((LONG *)(op + 12));
2742 LLength.LowPart = *((DWORD *)(op + 16));
2746 /* Not Large Files */
2747 LOffset.HighPart = 0;
2748 LOffset.LowPart = *((DWORD *)(op + 2));
2749 LLength.HighPart = 0;
2750 LLength.LowPart = *((DWORD *)(op + 6));
2753 if (LargeIntegerNotEqualToZero(LOffset))
2755 if (LargeIntegerLessThan(LOffset, scp->length))
2758 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2759 userp, &req, &lockp);
2760 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2761 /* Put on waiting list */
2762 waitingLock = malloc(sizeof(smb_waitingLock_t));
2763 waitingLock->vcp = vcp;
2764 waitingLock->inp = smb_CopyPacket(inp);
2765 waitingLock->outp = smb_CopyPacket(outp);
2766 waitingLock->timeRemaining = Timeout;
2767 waitingLock->lockp = lockp;
2768 lock_ObtainWrite(&smb_globalLock);
2769 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2771 osi_Wakeup((long) &smb_allWaitingLocks);
2772 lock_ReleaseWrite(&smb_globalLock);
2773 /* don't send reply immediately */
2774 outp->flags |= SMB_PACKETFLAG_NOSEND;
2780 /* release any locks acquired before the failure */
2783 smb_SetSMBDataLength(outp, 0);
2785 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2787 lock_ReleaseMutex(&scp->mx);
2788 cm_ReleaseUser(userp);
2789 smb_ReleaseFID(fidp);
2794 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2806 fid = smb_GetSMBParm(inp, 0);
2807 fid = smb_ChainFID(fid, inp);
2809 fidp = smb_FindFID(vcp, fid, 0);
2810 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2811 return CM_ERROR_BADFD;
2814 userp = smb_GetUser(vcp, inp);
2818 /* otherwise, stat the file */
2819 lock_ObtainMutex(&scp->mx);
2820 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2821 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2822 if (code) goto done;
2824 /* decode times. We need a search time, but the response to this
2825 * call provides the date first, not the time, as returned in the
2826 * searchTime variable. So we take the high-order bits first.
2828 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2829 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
2830 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2831 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
2832 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2833 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
2834 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2836 /* now handle file size and allocation size */
2837 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
2838 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2839 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
2840 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2842 /* file attribute */
2843 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2845 /* and finalize stuff */
2846 smb_SetSMBDataLength(outp, 0);
2850 lock_ReleaseMutex(&scp->mx);
2851 cm_ReleaseUser(userp);
2852 smb_ReleaseFID(fidp);
2856 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2870 fid = smb_GetSMBParm(inp, 0);
2871 fid = smb_ChainFID(fid, inp);
2873 fidp = smb_FindFID(vcp, fid, 0);
2874 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2875 return CM_ERROR_BADFD;
2878 userp = smb_GetUser(vcp, inp);
2882 /* now prepare to call cm_setattr. This message only sets various times,
2883 * and AFS only implements mtime, and we'll set the mtime if that's
2884 * requested. The others we'll ignore.
2886 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
2888 if (searchTime != 0) {
2889 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
2890 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
2891 attrs.clientModTime = unixTime;
2892 code = cm_SetAttr(scp, &attrs, userp, &req);
2896 cm_ReleaseUser(userp);
2897 smb_ReleaseFID(fidp);
2902 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2905 long count, finalCount;
2912 fd = smb_GetSMBParm(inp, 2);
2913 count = smb_GetSMBParm(inp, 5);
2914 offset.HighPart = 0; /* too bad */
2915 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
2917 osi_Log3(afsd_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
2918 fd, offset.LowPart, count);
2920 fd = smb_ChainFID(fd, inp);
2921 fidp = smb_FindFID(vcp, fd, 0);
2923 return CM_ERROR_BADFD;
2925 /* set inp->fid so that later read calls in same msg can find fid */
2928 if (fidp->flags & SMB_FID_IOCTL) {
2929 return smb_IoctlV3Read(fidp, vcp, inp, outp);
2932 userp = smb_GetUser(vcp, inp);
2934 /* 0 and 1 are reserved for request chaining, were setup by our caller,
2935 * and will be further filled in after we return.
2937 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
2938 smb_SetSMBParm(outp, 3, 0); /* resvd */
2939 smb_SetSMBParm(outp, 4, 0); /* resvd */
2940 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
2941 /* fill in #6 when we have all the parameters' space reserved */
2942 smb_SetSMBParm(outp, 7, 0); /* resv'd */
2943 smb_SetSMBParm(outp, 8, 0); /* resv'd */
2944 smb_SetSMBParm(outp, 9, 0); /* resv'd */
2945 smb_SetSMBParm(outp, 10, 0); /* resv'd */
2946 smb_SetSMBParm(outp, 11, 0); /* reserved */
2948 /* get op ptr after putting in the parms, since otherwise we don't
2949 * know where the data really is.
2951 op = smb_GetSMBData(outp, NULL);
2953 /* now fill in offset from start of SMB header to first data byte (to op) */
2954 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
2956 /* set the packet data length the count of the # of bytes */
2957 smb_SetSMBDataLength(outp, count);
2960 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
2962 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
2965 /* fix some things up */
2966 smb_SetSMBParm(outp, 5, finalCount);
2967 smb_SetSMBDataLength(outp, finalCount);
2969 smb_ReleaseFID(fidp);
2971 cm_ReleaseUser(userp);
2976 * Values for createDisp, copied from NTDDK.H
2978 * FILE_SUPERSEDE 0 (???)
2979 * FILE_OPEN 1 (open)
2980 * FILE_CREATE 2 (exclusive)
2981 * FILE_OPEN_IF 3 (non-exclusive)
2982 * FILE_OVERWRITE 4 (open & truncate, but do not create)
2983 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
2986 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2988 char *pathp, *realPathp;
2992 cm_scache_t *dscp; /* parent dir */
2993 cm_scache_t *scp; /* file to create or open */
2996 unsigned short nameLength;
2998 unsigned int requestOpLock;
2999 unsigned int requestBatchOpLock;
3000 unsigned int mustBeDir;
3002 unsigned int desiredAccess;
3003 unsigned int extAttributes;
3004 unsigned int createDisp;
3005 unsigned int createOptions;
3006 int initialModeBits;
3007 unsigned short baseFid;
3008 smb_fid_t *baseFidp;
3010 cm_scache_t *baseDirp;
3011 unsigned short openAction;
3025 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3026 flags = smb_GetSMBOffsetParm(inp, 3, 1)
3027 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3028 requestOpLock = flags & 0x02;
3029 requestBatchOpLock = flags & 0x04;
3030 mustBeDir = flags & 0x08;
3033 * Why all of a sudden 32-bit FID?
3034 * We will reject all bits higher than 16.
3036 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3037 return CM_ERROR_INVAL;
3038 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3039 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3040 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3041 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3042 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3043 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3044 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3045 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3046 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3048 /* mustBeDir is never set; createOptions directory bit seems to be
3051 if (createOptions & 1)
3053 else if (createOptions & 0x40)
3059 * compute initial mode bits based on read-only flag in
3060 * extended attributes
3062 initialModeBits = 0666;
3063 if (extAttributes & 1) initialModeBits &= ~0222;
3065 pathp = smb_GetSMBData(inp, NULL);
3066 /* Sometimes path is not null-terminated, so we make a copy. */
3067 realPathp = malloc(nameLength+1);
3068 memcpy(realPathp, pathp, nameLength);
3069 realPathp[nameLength] = 0;
3071 spacep = inp->spacep;
3072 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3074 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3075 /* special case magic file name for receiving IOCTL requests
3076 * (since IOCTL calls themselves aren't getting through).
3078 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3079 smb_SetupIoctlFid(fidp, spacep);
3081 /* set inp->fid so that later read calls in same msg can find fid */
3082 inp->fid = fidp->fid;
3086 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3087 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3088 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3090 memset(&ft, 0, sizeof(ft));
3091 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3092 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3093 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3094 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3095 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3096 sz.HighPart = 0x7fff; sz.LowPart = 0;
3097 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3098 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3099 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3100 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3101 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
3102 smb_SetSMBDataLength(outp, 0);
3104 /* clean up fid reference */
3105 smb_ReleaseFID(fidp);
3110 userp = smb_GetUser(vcp, inp);
3113 baseDirp = cm_rootSCachep;
3114 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3117 baseFidp = smb_FindFID(vcp, baseFid, 0);
3118 baseDirp = baseFidp->scp;
3122 /* compute open mode */
3124 if (desiredAccess & DELETE)
3125 fidflags |= SMB_FID_OPENDELETE;
3126 if (desiredAccess & AFS_ACCESS_READ)
3127 fidflags |= SMB_FID_OPENREAD;
3128 if (desiredAccess & AFS_ACCESS_WRITE)
3129 fidflags |= SMB_FID_OPENWRITE;
3133 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3134 userp, tidPathp, &req, &scp);
3135 if (code == 0) foundscp = TRUE;
3137 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3138 /* look up parent directory */
3139 code = cm_NameI(baseDirp, spacep->data,
3140 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_CHECKPATH,
3141 userp, tidPathp, &req, &dscp);
3143 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3146 cm_ReleaseUser(userp);
3151 if (!lastNamep) lastNamep = realPathp;
3154 if (!smb_IsLegalFilename(lastNamep))
3155 return CM_ERROR_BADNTFILENAME;
3158 code = cm_Lookup(dscp, lastNamep,
3159 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3161 if (code && code != CM_ERROR_NOSUCHFILE) {
3162 cm_ReleaseSCache(dscp);
3163 cm_ReleaseUser(userp);
3170 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3173 /* if we get here, if code is 0, the file exists and is represented by
3174 * scp. Otherwise, we have to create it. The dir may be represented
3175 * by dscp, or we may have found the file directly. If code is non-zero,
3179 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3182 if (dscp) cm_ReleaseSCache(dscp);
3183 cm_ReleaseSCache(scp);
3184 cm_ReleaseUser(userp);
3189 if (createDisp == 2) {
3190 /* oops, file shouldn't be there */
3191 if (dscp) cm_ReleaseSCache(dscp);
3192 cm_ReleaseSCache(scp);
3193 cm_ReleaseUser(userp);
3195 return CM_ERROR_EXISTS;
3199 || createDisp == 5) {
3200 setAttr.mask = CM_ATTRMASK_LENGTH;
3201 setAttr.length.LowPart = 0;
3202 setAttr.length.HighPart = 0;
3203 code = cm_SetAttr(scp, &setAttr, userp, &req);
3204 openAction = 3; /* truncated existing file */
3206 else openAction = 1; /* found existing file */
3208 else if (createDisp == 1 || createDisp == 4) {
3209 /* don't create if not found */
3210 if (dscp) cm_ReleaseSCache(dscp);
3211 cm_ReleaseUser(userp);
3213 return CM_ERROR_NOSUCHFILE;
3215 else if (realDirFlag == 0 || realDirFlag == -1) {
3216 osi_assert(dscp != NULL);
3217 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating file %s",
3218 osi_LogSaveString(afsd_logp, lastNamep));
3219 openAction = 2; /* created file */
3220 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3221 setAttr.clientModTime = time(NULL);
3222 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3224 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3225 smb_NotifyChange(FILE_ACTION_ADDED,
3226 FILE_NOTIFY_CHANGE_FILE_NAME,
3227 dscp, lastNamep, NULL, TRUE);
3228 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3229 /* Not an exclusive create, and someone else tried
3230 * creating it already, then we open it anyway. We
3231 * don't bother retrying after this, since if this next
3232 * fails, that means that the file was deleted after we
3233 * started this call.
3235 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3238 if (createDisp == 5) {
3239 setAttr.mask = CM_ATTRMASK_LENGTH;
3240 setAttr.length.LowPart = 0;
3241 setAttr.length.HighPart = 0;
3242 code = cm_SetAttr(scp, &setAttr, userp,
3245 } /* lookup succeeded */
3249 /* create directory */
3250 osi_assert(dscp != NULL);
3251 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating directory %s",
3252 osi_LogSaveString(afsd_logp, lastNamep));
3253 openAction = 2; /* created directory */
3254 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3255 setAttr.clientModTime = time(NULL);
3256 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3257 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3258 smb_NotifyChange(FILE_ACTION_ADDED,
3259 FILE_NOTIFY_CHANGE_DIR_NAME,
3260 dscp, lastNamep, NULL, TRUE);
3262 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3263 /* Not an exclusive create, and someone else tried
3264 * creating it already, then we open it anyway. We
3265 * don't bother retrying after this, since if this next
3266 * fails, that means that the file was deleted after we
3267 * started this call.
3269 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3275 /* something went wrong creating or truncating the file */
3276 if (scp) cm_ReleaseSCache(scp);
3277 cm_ReleaseUser(userp);
3282 /* make sure we have file vs. dir right */
3283 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3284 cm_ReleaseSCache(scp);
3285 cm_ReleaseUser(userp);
3287 return CM_ERROR_ISDIR;
3289 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3290 cm_ReleaseSCache(scp);
3291 cm_ReleaseUser(userp);
3293 return CM_ERROR_NOTDIR;
3296 /* open the file itself */
3297 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3299 /* save a pointer to the vnode */
3302 fidp->flags = fidflags;
3304 /* save parent dir and pathname for delete or change notification */
3305 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3306 fidp->flags |= SMB_FID_NTOPEN;
3307 fidp->NTopen_dscp = dscp;
3308 cm_HoldSCache(dscp);
3309 fidp->NTopen_pathp = strdup(lastNamep);
3311 fidp->NTopen_wholepathp = realPathp;
3313 /* we don't need this any longer */
3314 if (dscp) cm_ReleaseSCache(dscp);
3315 cm_Open(scp, 0, userp);
3317 /* set inp->fid so that later read calls in same msg can find fid */
3318 inp->fid = fidp->fid;
3322 lock_ObtainMutex(&scp->mx);
3323 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3324 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3325 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3326 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3327 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3328 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3329 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3330 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3331 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3333 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3334 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3335 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3336 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3337 smb_SetSMBParmByte(outp, parmSlot,
3338 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3339 lock_ReleaseMutex(&scp->mx);
3340 smb_SetSMBDataLength(outp, 0);
3342 osi_Log2(afsd_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3343 osi_LogSaveString(afsd_logp, realPathp));
3345 smb_ReleaseFID(fidp);
3347 cm_ReleaseUser(userp);
3349 /* leave scp held since we put it in fidp->scp */
3354 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3355 * Instead, ultimately, would like to use a subroutine for common code.
3357 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3359 char *pathp, *realPathp;
3363 cm_scache_t *dscp; /* parent dir */
3364 cm_scache_t *scp; /* file to create or open */
3367 unsigned long nameLength;
3369 unsigned int requestOpLock;
3370 unsigned int requestBatchOpLock;
3371 unsigned int mustBeDir;
3373 unsigned int desiredAccess;
3374 unsigned int extAttributes;
3375 unsigned int createDisp;
3376 unsigned int createOptions;
3377 int initialModeBits;
3378 unsigned short baseFid;
3379 smb_fid_t *baseFidp;
3381 cm_scache_t *baseDirp;
3382 unsigned short openAction;
3388 int parmOffset, dataOffset;
3399 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3400 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3401 parmp = inp->data + parmOffset;
3402 lparmp = (ULONG *) parmp;
3405 requestOpLock = flags & 0x02;
3406 requestBatchOpLock = flags & 0x04;
3407 mustBeDir = flags & 0x08;
3409 * Why all of a sudden 32-bit FID?
3410 * We will reject all bits higher than 16.
3412 if (lparmp[1] & 0xFFFF0000)
3413 return CM_ERROR_INVAL;
3414 baseFid = (unsigned short)lparmp[1];
3415 desiredAccess = lparmp[2];
3416 extAttributes = lparmp[5];
3417 createDisp = lparmp[7];
3418 createOptions = lparmp[8];
3419 nameLength = lparmp[11];
3421 /* mustBeDir is never set; createOptions directory bit seems to be
3424 if (createOptions & 1)
3426 else if (createOptions & 0x40)
3432 * compute initial mode bits based on read-only flag in
3433 * extended attributes
3435 initialModeBits = 0666;
3436 if (extAttributes & 1) initialModeBits &= ~0222;
3438 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3439 /* Sometimes path is not null-terminated, so we make a copy. */
3440 realPathp = malloc(nameLength+1);
3441 memcpy(realPathp, pathp, nameLength);
3442 realPathp[nameLength] = 0;
3444 spacep = cm_GetSpace();
3445 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3448 * Nothing here to handle SMB_IOCTL_FILENAME.
3449 * Will add it if necessary.
3452 userp = smb_GetUser(vcp, inp);
3455 baseDirp = cm_rootSCachep;
3456 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3459 baseFidp = smb_FindFID(vcp, baseFid, 0);
3460 baseDirp = baseFidp->scp;
3464 /* compute open mode */
3466 if (desiredAccess & DELETE)
3467 fidflags |= SMB_FID_OPENDELETE;
3468 if (desiredAccess & AFS_ACCESS_READ)
3469 fidflags |= SMB_FID_OPENREAD;
3470 if (desiredAccess & AFS_ACCESS_WRITE)
3471 fidflags |= SMB_FID_OPENWRITE;
3475 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3476 userp, tidPathp, &req, &scp);
3477 if (code == 0) foundscp = TRUE;
3479 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3480 /* look up parent directory */
3481 code = cm_NameI(baseDirp, spacep->data,
3482 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3483 userp, tidPathp, &req, &dscp);
3484 cm_FreeSpace(spacep);
3486 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3489 cm_ReleaseUser(userp);
3494 if (!lastNamep) lastNamep = realPathp;
3497 if (!smb_IsLegalFilename(lastNamep))
3498 return CM_ERROR_BADNTFILENAME;
3501 code = cm_Lookup(dscp, lastNamep,
3502 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3504 if (code && code != CM_ERROR_NOSUCHFILE) {
3505 cm_ReleaseSCache(dscp);
3506 cm_ReleaseUser(userp);
3513 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3514 cm_FreeSpace(spacep);
3517 /* if we get here, if code is 0, the file exists and is represented by
3518 * scp. Otherwise, we have to create it. The dir may be represented
3519 * by dscp, or we may have found the file directly. If code is non-zero,
3523 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3526 if (dscp) cm_ReleaseSCache(dscp);
3527 cm_ReleaseSCache(scp);
3528 cm_ReleaseUser(userp);
3533 if (createDisp == 2) {
3534 /* oops, file shouldn't be there */
3535 if (dscp) cm_ReleaseSCache(dscp);
3536 cm_ReleaseSCache(scp);
3537 cm_ReleaseUser(userp);
3539 return CM_ERROR_EXISTS;
3543 || createDisp == 5) {
3544 setAttr.mask = CM_ATTRMASK_LENGTH;
3545 setAttr.length.LowPart = 0;
3546 setAttr.length.HighPart = 0;
3547 code = cm_SetAttr(scp, &setAttr, userp, &req);
3548 openAction = 3; /* truncated existing file */
3550 else openAction = 1; /* found existing file */
3552 else if (createDisp == 1 || createDisp == 4) {
3553 /* don't create if not found */
3554 if (dscp) cm_ReleaseSCache(dscp);
3555 cm_ReleaseUser(userp);
3557 return CM_ERROR_NOSUCHFILE;
3559 else if (realDirFlag == 0 || realDirFlag == -1) {
3560 osi_assert(dscp != NULL);
3561 osi_Log1(afsd_logp, "smb_ReceiveNTTranCreate creating file %s",
3562 osi_LogSaveString(afsd_logp, lastNamep));
3563 openAction = 2; /* created file */
3564 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3565 setAttr.clientModTime = time(NULL);
3566 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3568 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3569 smb_NotifyChange(FILE_ACTION_ADDED,
3570 FILE_NOTIFY_CHANGE_FILE_NAME,
3571 dscp, lastNamep, NULL, TRUE);
3572 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3573 /* Not an exclusive create, and someone else tried
3574 * creating it already, then we open it anyway. We
3575 * don't bother retrying after this, since if this next
3576 * fails, that means that the file was deleted after we
3577 * started this call.
3579 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3582 if (createDisp == 5) {
3583 setAttr.mask = CM_ATTRMASK_LENGTH;
3584 setAttr.length.LowPart = 0;
3585 setAttr.length.HighPart = 0;
3586 code = cm_SetAttr(scp, &setAttr, userp,
3589 } /* lookup succeeded */
3593 /* create directory */
3594 osi_assert(dscp != NULL);
3596 "smb_ReceiveNTTranCreate creating directory %s",
3597 osi_LogSaveString(afsd_logp, lastNamep));
3598 openAction = 2; /* created directory */
3599 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3600 setAttr.clientModTime = time(NULL);
3601 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3602 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3603 smb_NotifyChange(FILE_ACTION_ADDED,
3604 FILE_NOTIFY_CHANGE_DIR_NAME,
3605 dscp, lastNamep, NULL, TRUE);
3607 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3608 /* Not an exclusive create, and someone else tried
3609 * creating it already, then we open it anyway. We
3610 * don't bother retrying after this, since if this next
3611 * fails, that means that the file was deleted after we
3612 * started this call.
3614 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3620 /* something went wrong creating or truncating the file */
3621 if (scp) cm_ReleaseSCache(scp);
3622 cm_ReleaseUser(userp);
3627 /* make sure we have file vs. dir right */
3628 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3629 cm_ReleaseSCache(scp);
3630 cm_ReleaseUser(userp);
3632 return CM_ERROR_ISDIR;
3634 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3635 cm_ReleaseSCache(scp);
3636 cm_ReleaseUser(userp);
3638 return CM_ERROR_NOTDIR;
3641 /* open the file itself */
3642 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3645 /* save a pointer to the vnode */
3648 fidp->flags = fidflags;
3650 /* save parent dir and pathname for deletion or change notification */
3651 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3652 fidp->flags |= SMB_FID_NTOPEN;
3653 fidp->NTopen_dscp = dscp;
3654 cm_HoldSCache(dscp);
3655 fidp->NTopen_pathp = strdup(lastNamep);
3657 fidp->NTopen_wholepathp = realPathp;
3659 /* we don't need this any longer */
3660 if (dscp) cm_ReleaseSCache(dscp);
3662 cm_Open(scp, 0, userp);
3664 /* set inp->fid so that later read calls in same msg can find fid */
3665 inp->fid = fidp->fid;
3668 parmOffset = 8*4 + 39;
3669 parmOffset += 1; /* pad to 4 */
3670 dataOffset = parmOffset + 70;
3674 /* Total Parameter Count */
3675 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3676 /* Total Data Count */
3677 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3678 /* Parameter Count */
3679 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3680 /* Parameter Offset */
3681 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3682 /* Parameter Displacement */
3683 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3685 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3687 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3688 /* Data Displacement */
3689 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3690 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
3691 smb_SetSMBDataLength(outp, 70);
3693 lock_ObtainMutex(&scp->mx);
3694 outData = smb_GetSMBData(outp, NULL);
3695 outData++; /* round to get to parmOffset */
3696 *outData = 0; outData++; /* oplock */
3697 *outData = 0; outData++; /* reserved */
3698 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
3699 *((ULONG *)outData) = openAction; outData += 4;
3700 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
3701 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3702 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
3703 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
3704 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
3705 *((FILETIME *)outData) = ft; outData += 8; /* change time */
3706 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
3707 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
3708 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
3709 *((USHORT *)outData) = 0; outData += 2; /* filetype */
3710 *((USHORT *)outData) = 0; outData += 2; /* dev state */
3711 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
3712 outData += 2; /* is a dir? */
3713 lock_ReleaseMutex(&scp->mx);
3715 osi_Log1(afsd_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
3717 smb_ReleaseFID(fidp);
3719 cm_ReleaseUser(userp);
3721 /* leave scp held since we put it in fidp->scp */
3725 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
3728 smb_packet_t *savedPacketp;
3729 ULONG filter; USHORT fid, watchtree;
3733 filter = smb_GetSMBParm(inp, 19)
3734 | (smb_GetSMBParm(inp, 20) << 16);
3735 fid = smb_GetSMBParm(inp, 21);
3736 watchtree = smb_GetSMBParm(inp, 22) && 0xffff;
3738 savedPacketp = smb_CopyPacket(inp);
3739 savedPacketp->vcp = vcp;
3740 lock_ObtainMutex(&smb_Dir_Watch_Lock);
3741 savedPacketp->nextp = smb_Directory_Watches;
3742 smb_Directory_Watches = savedPacketp;
3743 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
3745 fidp = smb_FindFID(vcp, fid, 0);
3747 osi_Log4(afsd_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
3748 filter, fid, watchtree, osi_LogSaveString(afsd_logp, fidp->NTopen_wholepathp));
3751 lock_ObtainMutex(&scp->mx);
3753 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
3755 scp->flags |= CM_SCACHEFLAG_WATCHED;
3756 lock_ReleaseMutex(&scp->mx);
3757 smb_ReleaseFID(fidp);
3759 outp->flags |= SMB_PACKETFLAG_NOSEND;
3764 unsigned char nullSecurityDesc[36] = {
3765 0x01, /* security descriptor revision */
3766 0x00, /* reserved, should be zero */
3767 0x00, 0x80, /* security descriptor control;
3768 * 0x8000 : self-relative format */
3769 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
3770 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
3771 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
3772 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
3773 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3774 /* "null SID" owner SID */
3775 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
3776 /* "null SID" group SID */
3779 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3781 int parmOffset, parmCount, dataOffset, dataCount;
3789 ULONG securityInformation;
3791 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3792 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3793 parmp = inp->data + parmOffset;
3794 sparmp = (USHORT *) parmp;
3795 lparmp = (ULONG *) parmp;
3798 securityInformation = lparmp[1];
3800 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
3801 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3809 parmOffset = 8*4 + 39;
3810 parmOffset += 1; /* pad to 4 */
3812 dataOffset = parmOffset + parmCount;
3816 /* Total Parameter Count */
3817 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
3818 /* Total Data Count */
3819 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
3820 /* Parameter Count */
3821 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
3822 /* Parameter Offset */
3823 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3824 /* Parameter Displacement */
3825 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3827 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
3829 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3830 /* Data Displacement */
3831 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3832 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
3833 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
3835 outData = smb_GetSMBData(outp, NULL);
3836 outData++; /* round to get to parmOffset */
3837 *((ULONG *)outData) = 36; outData += 4; /* length */
3839 if (maxData >= 36) {
3840 memcpy(outData, nullSecurityDesc, 36);
3844 return CM_ERROR_BUFFERTOOSMALL;
3847 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3849 unsigned short function;
3851 function = smb_GetSMBParm(inp, 18);
3853 osi_Log1(afsd_logp, "SMB NT Transact function %d", function);
3855 /* We can handle long names */
3856 if (vcp->flags & SMB_VCFLAG_USENT)
3857 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3861 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
3863 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
3865 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
3867 default: return CM_ERROR_INVAL;
3872 * smb_NotifyChange -- find relevant change notification messages and
3875 * If we don't know the file name (i.e. a callback break), filename is
3876 * NULL, and we return a zero-length list.
3878 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
3879 cm_scache_t *dscp, char *filename, char *otherFilename,
3880 BOOL isDirectParent)
3882 smb_packet_t *watch, *lastWatch, *nextWatch;
3883 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
3884 char *outData, *oldOutData;
3888 BOOL twoEntries = FALSE;
3889 ULONG otherNameLen, oldParmCount = 0;
3894 /* Get ready for rename within directory */
3895 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
3897 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
3900 lock_ObtainMutex(&smb_Dir_Watch_Lock);
3901 watch = smb_Directory_Watches;
3903 filter = smb_GetSMBParm(watch, 19)
3904 | (smb_GetSMBParm(watch, 20) << 16);
3905 fid = smb_GetSMBParm(watch, 21);
3906 wtree = smb_GetSMBParm(watch, 22) & 0xffff;
3907 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
3908 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
3912 * Strange hack - bug in NT Client and NT Server that we
3915 if (filter == 3 && wtree)
3918 fidp = smb_FindFID(vcp, fid, 0);
3919 if (fidp->scp != dscp
3920 || (filter & notifyFilter) == 0
3921 || (!isDirectParent && !wtree)) {
3922 smb_ReleaseFID(fidp);
3924 watch = watch->nextp;
3927 smb_ReleaseFID(fidp);
3930 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
3931 fid, filter, wtree, osi_LogSaveString(afsd_logp, filename));
3933 nextWatch = watch->nextp;
3934 if (watch == smb_Directory_Watches)
3935 smb_Directory_Watches = nextWatch;
3937 lastWatch->nextp = nextWatch;
3939 /* Turn off WATCHED flag in dscp */
3940 lock_ObtainMutex(&dscp->mx);
3942 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
3944 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
3945 lock_ReleaseMutex(&dscp->mx);
3947 /* Convert to response packet */
3948 ((smb_t *) watch)->reb = 0x80;
3949 ((smb_t *) watch)->wct = 0;
3952 if (filename == NULL)
3955 nameLen = strlen(filename);
3956 parmCount = 3*4 + nameLen*2;
3957 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
3959 otherNameLen = strlen(otherFilename);
3960 oldParmCount = parmCount;
3961 parmCount += 3*4 + otherNameLen*2;
3962 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
3964 if (maxLen < parmCount)
3965 parmCount = 0; /* not enough room */
3967 parmOffset = 8*4 + 39;
3968 parmOffset += 1; /* pad to 4 */
3969 dataOffset = parmOffset + parmCount;
3973 /* Total Parameter Count */
3974 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
3975 /* Total Data Count */
3976 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
3977 /* Parameter Count */
3978 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
3979 /* Parameter Offset */
3980 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
3981 /* Parameter Displacement */
3982 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
3984 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
3986 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
3987 /* Data Displacement */
3988 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
3989 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
3990 smb_SetSMBDataLength(watch, parmCount + 1);
3992 if (parmCount != 0) {
3993 outData = smb_GetSMBData(watch, NULL);
3994 outData++; /* round to get to parmOffset */
3995 oldOutData = outData;
3996 *((DWORD *)outData) = oldParmCount; outData += 4;
3997 /* Next Entry Offset */
3998 *((DWORD *)outData) = action; outData += 4;
4000 *((DWORD *)outData) = nameLen*2; outData += 4;
4001 /* File Name Length */
4002 mbstowcs((WCHAR *)outData, filename, nameLen);
4005 outData = oldOutData + oldParmCount;
4006 *((DWORD *)outData) = 0; outData += 4;
4007 /* Next Entry Offset */
4008 *((DWORD *)outData) = otherAction; outData += 4;
4010 *((DWORD *)outData) = otherNameLen*2;
4011 outData += 4; /* File Name Length */
4012 mbstowcs((WCHAR *)outData, otherFilename,
4013 otherNameLen); /* File Name */
4018 * If filename is null, we don't know the cause of the
4019 * change notification. We return zero data (see above),
4020 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
4021 * (= 0x010C). We set the error code here by hand, without
4022 * modifying wct and bcc.
4024 if (filename == NULL) {
4025 ((smb_t *) watch)->rcls = 0x0C;
4026 ((smb_t *) watch)->reh = 0x01;
4027 ((smb_t *) watch)->errLow = 0;
4028 ((smb_t *) watch)->errHigh = 0;
4029 /* Set NT Status codes flag */
4030 ((smb_t *) watch)->flg2 |= 0x4000;
4033 smb_SendPacket(vcp, watch);
4034 smb_FreePacket(watch);
4037 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4040 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4042 unsigned char *replyWctp;
4043 smb_packet_t *watch, *lastWatch;
4044 USHORT fid, watchtree;
4048 osi_Log0(afsd_logp, "SMB3 receive NT cancel");
4050 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4051 watch = smb_Directory_Watches;
4053 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
4054 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
4055 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
4056 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
4057 if (watch == smb_Directory_Watches)
4058 smb_Directory_Watches = watch->nextp;
4060 lastWatch->nextp = watch->nextp;
4061 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4063 /* Turn off WATCHED flag in scp */
4064 fid = smb_GetSMBParm(watch, 21);
4065 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
4067 fidp = smb_FindFID(vcp, fid, 0);
4069 osi_Log3(afsd_logp, "Cancelling change notification for fid %d wtree %d file %s",
4071 osi_LogSaveString(afsd_logp, (fidp)?fidp->NTopen_wholepathp:""));
4074 lock_ObtainMutex(&scp->mx);
4076 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4078 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
4079 lock_ReleaseMutex(&scp->mx);
4080 smb_ReleaseFID(fidp);
4082 /* assume STATUS32; return 0xC0000120 (CANCELED) */
4083 replyWctp = watch->wctp;
4087 ((smb_t *)watch)->rcls = 0x20;
4088 ((smb_t *)watch)->reh = 0x1;
4089 ((smb_t *)watch)->errLow = 0;
4090 ((smb_t *)watch)->errHigh = 0xC0;
4091 ((smb_t *)watch)->flg2 |= 0x4000;
4092 smb_SendPacket(vcp, watch);
4093 smb_FreePacket(watch);
4097 watch = watch->nextp;
4099 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4106 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
4109 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
4113 smb_username_t *unp;
4115 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
4117 lock_ObtainMutex(&unp->mx);
4118 unp->userp = cm_NewUser();
4119 lock_ReleaseMutex(&unp->mx);
4120 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
4122 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);