2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
28 extern osi_hyper_t hzero;
30 smb_packet_t *smb_Directory_Watches = NULL;
31 osi_mutex_t smb_Dir_Watch_Lock;
33 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
35 /* protected by the smb_globalLock */
36 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
38 /* retrieve a held reference to a user structure corresponding to an incoming
40 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
45 uidp = smb_FindUID(vcp, inp->uid, 0);
46 if (!uidp) return NULL;
48 lock_ObtainMutex(&uidp->mx);
50 up = uidp->unp->userp;
53 lock_ReleaseMutex(&uidp->mx);
61 * Return extended attributes.
62 * Right now, we aren't using any of the "new" bits, so this looks exactly
63 * like smb_Attributes() (see smb.c).
65 unsigned long smb_ExtAttributes(cm_scache_t *scp)
69 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
70 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
71 attrs = SMB_ATTR_DIRECTORY;
75 * We used to mark a file RO if it was in an RO volume, but that
76 * turns out to be impolitic in NT. See defect 10007.
79 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
81 if ((scp->unixModeBits & 0222) == 0)
82 attrs |= SMB_ATTR_READONLY; /* Read-only */
85 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
90 int smb_V3IsStarMask(char *maskp)
95 if (tc == '?' || tc == '*')
100 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
103 /* skip over null-terminated string */
104 *chainpp = inp + strlen(inp) + 1;
109 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
112 char *usern, *pwd, *pwdx;
114 unsigned short newUid;
120 /* Check for bad conns */
121 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
122 return CM_ERROR_REMOTECONN;
124 /* For NT LM 0.12 and up, get capabilities */
125 if (vcp->flags & SMB_VCFLAG_USENT) {
126 caps = smb_GetSMBParm(inp, 11);
128 vcp->flags |= SMB_VCFLAG_STATUS32;
129 /* for now, ignore other capability bits */
133 tp = smb_GetSMBData(inp, NULL);
134 if (vcp->flags & SMB_VCFLAG_USENT)
135 pwdx = smb_ParseString(tp, &tp);
136 pwd = smb_ParseString(tp, &tp);
137 usern = smb_ParseString(tp, &tp);
139 /* On Windows 2000, this function appears to be called more often than
140 it is expected to be called. This resulted in multiple smb_user_t
141 records existing all for the same user session which results in all
142 of the users tokens disappearing.
144 To avoid this problem, we look for an existing smb_user_t record
145 based on the users name, and use that one if we find it.
148 uidp = smb_FindUserByNameThisSession(vcp, usern);
149 if (uidp) { /* already there, so don't create a new one */
152 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
153 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,usern);
154 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
155 smb_ReleaseUID(uidp);
158 /* do a global search for the username/machine name pair */
159 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
161 /* Create a new UID and cm_user_t structure */
164 userp = cm_NewUser();
165 lock_ObtainMutex(&vcp->mx);
166 if (!vcp->uidCounter)
167 vcp->uidCounter++; /* handle unlikely wraparounds */
168 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
169 lock_ReleaseMutex(&vcp->mx);
171 /* Create a new smb_user_t structure and connect them up */
172 lock_ObtainMutex(&unp->mx);
174 lock_ReleaseMutex(&unp->mx);
176 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
177 lock_ObtainMutex(&uidp->mx);
179 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);
180 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
181 lock_ReleaseMutex(&uidp->mx);
182 smb_ReleaseUID(uidp);
185 /* Return UID to the client */
186 ((smb_t *)outp)->uid = newUid;
187 /* Also to the next chained message */
188 ((smb_t *)inp)->uid = newUid;
190 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
191 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
192 smb_SetSMBParm(outp, 2, 0);
193 smb_SetSMBDataLength(outp, 0);
197 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
201 /* don't get tokens from this VC */
202 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
204 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
206 /* find the tree and free it */
207 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
208 /* TODO: smb_ReleaseUID() ? */
210 char *s1 = NULL, *s2 = NULL;
212 if (s2 == NULL) s2 = " ";
213 if (s1 == NULL) {s1 = s2; s2 = " ";}
215 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s",
217 osi_LogSaveString(smb_logp,
218 (uidp->unp) ? uidp->unp->name: " "), s1, s2);
220 lock_ObtainMutex(&uidp->mx);
221 uidp->flags |= SMB_USERFLAG_DELETE;
223 * it doesn't get deleted right away
224 * because the vcp points to it
226 lock_ReleaseMutex(&uidp->mx);
229 osi_Log0(smb_logp, "SMB3 user logoffX");
231 smb_SetSMBDataLength(outp, 0);
235 #define SMB_SUPPORT_SEARCH_BITS 0x0001
237 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
241 unsigned short newTid;
251 osi_Log0(smb_logp, "SMB3 receive tree connect");
253 /* parse input parameters */
254 tp = smb_GetSMBData(inp, NULL);
255 passwordp = smb_ParseString(tp, &tp);
256 pathp = smb_ParseString(tp, &tp);
257 servicep = smb_ParseString(tp, &tp);
259 tp = strrchr(pathp, '\\');
261 return CM_ERROR_BADSMB;
263 strcpy(shareName, tp+1);
265 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0)
266 return CM_ERROR_NOIPC;
268 userp = smb_GetUser(vcp, inp);
270 lock_ObtainMutex(&vcp->mx);
271 newTid = vcp->tidCounter++;
272 lock_ReleaseMutex(&vcp->mx);
274 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
275 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
276 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
278 smb_ReleaseUID(uidp);
280 smb_ReleaseTID(tidp);
281 return CM_ERROR_BADSHARENAME;
283 lock_ObtainMutex(&tidp->mx);
285 tidp->pathname = sharePath;
286 lock_ReleaseMutex(&tidp->mx);
287 smb_ReleaseTID(tidp);
289 if (vcp->flags & SMB_VCFLAG_USENT)
291 int policy = smb_FindShareCSCPolicy(shareName);
292 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy << 2));
295 ((smb_t *)outp)->tid = newTid;
296 ((smb_t *)inp)->tid = newTid;
297 tp = smb_GetSMBData(outp, NULL);
301 smb_SetSMBDataLength(outp, 3);
303 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
307 /* must be called with global tran lock held */
308 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
310 smb_tran2Packet_t *tp;
313 smbp = (smb_t *) inp->data;
314 for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
315 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
321 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
322 int totalParms, int totalData)
324 smb_tran2Packet_t *tp;
327 smbp = (smb_t *) inp->data;
328 tp = malloc(sizeof(*tp));
329 memset(tp, 0, sizeof(*tp));
332 tp->curData = tp->curParms = 0;
333 tp->totalData = totalData;
334 tp->totalParms = totalParms;
339 tp->res[0] = smbp->res[0];
340 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
341 tp->opcode = smb_GetSMBParm(inp, 14);
343 tp->parmsp = malloc(totalParms);
345 tp->datap = malloc(totalData);
346 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
350 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
351 smb_tran2Packet_t *inp, smb_packet_t *outp,
352 int totalParms, int totalData)
354 smb_tran2Packet_t *tp;
355 unsigned short parmOffset;
356 unsigned short dataOffset;
357 unsigned short dataAlign;
359 tp = malloc(sizeof(*tp));
360 memset(tp, 0, sizeof(*tp));
362 tp->curData = tp->curParms = 0;
363 tp->totalData = totalData;
364 tp->totalParms = totalParms;
365 tp->oldTotalParms = totalParms;
370 tp->res[0] = inp->res[0];
371 tp->opcode = inp->opcode;
374 * We calculate where the parameters and data will start.
375 * This calculation must parallel the calculation in
376 * smb_SendTran2Packet.
379 parmOffset = 10*2 + 35;
380 parmOffset++; /* round to even */
381 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
383 dataOffset = parmOffset + totalParms;
384 dataAlign = dataOffset & 2; /* quad-align */
385 dataOffset += dataAlign;
386 tp->datap = outp->data + dataOffset;
391 /* free a tran2 packet; must be called with smb_globalLock held */
392 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
394 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
395 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
404 /* called with a VC, an input packet to respond to, and an error code.
405 * sends an error response.
407 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
408 smb_packet_t *tp, long code)
411 unsigned short errCode;
412 unsigned char errClass;
413 unsigned long NTStatus;
415 if (vcp->flags & SMB_VCFLAG_STATUS32)
416 smb_MapNTError(code, &NTStatus);
418 smb_MapCoreError(code, vcp, &errCode, &errClass);
420 smb_FormatResponsePacket(vcp, NULL, tp);
423 /* We can handle long names */
424 if (vcp->flags & SMB_VCFLAG_USENT)
425 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
427 /* now copy important fields from the tran 2 packet */
428 smbp->com = 0x32; /* tran 2 response */
429 smbp->tid = t2p->tid;
430 smbp->mid = t2p->mid;
431 smbp->pid = t2p->pid;
432 smbp->uid = t2p->uid;
433 smbp->res[0] = t2p->res[0];
434 if (vcp->flags & SMB_VCFLAG_STATUS32) {
435 smbp->rcls = (unsigned char) (NTStatus & 0xff);
436 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
437 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
438 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
439 smbp->flg2 |= 0x4000;
442 smbp->rcls = errClass;
443 smbp->errLow = (unsigned char) (errCode & 0xff);
444 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
448 smb_SendPacket(vcp, tp);
451 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
454 unsigned short parmOffset;
455 unsigned short dataOffset;
456 unsigned short totalLength;
457 unsigned short dataAlign;
460 smb_FormatResponsePacket(vcp, NULL, tp);
463 /* We can handle long names */
464 if (vcp->flags & SMB_VCFLAG_USENT)
465 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
467 /* now copy important fields from the tran 2 packet */
468 smbp->com = 0x32; /* tran 2 response */
469 smbp->tid = t2p->tid;
470 smbp->mid = t2p->mid;
471 smbp->pid = t2p->pid;
472 smbp->uid = t2p->uid;
473 smbp->res[0] = t2p->res[0];
475 totalLength = 1 + t2p->totalData + t2p->totalParms;
477 /* now add the core parameters (tran2 info) to the packet */
478 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
479 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
480 smb_SetSMBParm(tp, 2, 0); /* reserved */
481 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
482 parmOffset = 10*2 + 35; /* parm offset in packet */
483 parmOffset++; /* round to even */
484 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
485 * hdr, bcc and wct */
486 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
487 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
488 dataOffset = parmOffset + t2p->oldTotalParms;
489 dataAlign = dataOffset & 2; /* quad-align */
490 dataOffset += dataAlign;
491 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
492 smb_SetSMBParm(tp, 8, 0); /* data displacement */
493 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
496 datap = smb_GetSMBData(tp, NULL);
497 *datap++ = 0; /* we rounded to even */
499 totalLength += dataAlign;
500 smb_SetSMBDataLength(tp, totalLength);
502 /* next, send the datagram */
503 smb_SendPacket(vcp, tp);
506 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
508 smb_tran2Packet_t *asp;
520 /* We sometimes see 0 word count. What to do? */
521 if (*inp->wctp == 0) {
526 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
528 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
529 ptbuf[0] = "Transaction2 word count = 0";
530 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
531 1, inp->ncb_length, ptbuf, inp);
532 DeregisterEventSource(h);
534 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
537 smb_SetSMBDataLength(outp, 0);
538 smb_SendPacket(vcp, outp);
542 totalParms = smb_GetSMBParm(inp, 0);
543 totalData = smb_GetSMBParm(inp, 1);
545 firstPacket = (inp->inCom == 0x32);
547 /* find the packet we're reassembling */
548 lock_ObtainWrite(&smb_globalLock);
549 asp = smb_FindTran2Packet(vcp, inp);
551 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
553 lock_ReleaseWrite(&smb_globalLock);
555 /* now merge in this latest packet; start by looking up offsets */
557 parmDisp = dataDisp = 0;
558 parmOffset = smb_GetSMBParm(inp, 10);
559 dataOffset = smb_GetSMBParm(inp, 12);
560 parmCount = smb_GetSMBParm(inp, 9);
561 dataCount = smb_GetSMBParm(inp, 11);
562 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
563 asp->maxReturnData = smb_GetSMBParm(inp, 3);
565 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
566 totalData, dataCount, asp->maxReturnData);
569 parmDisp = smb_GetSMBParm(inp, 4);
570 parmOffset = smb_GetSMBParm(inp, 3);
571 dataDisp = smb_GetSMBParm(inp, 7);
572 dataOffset = smb_GetSMBParm(inp, 6);
573 parmCount = smb_GetSMBParm(inp, 2);
574 dataCount = smb_GetSMBParm(inp, 5);
576 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
577 parmCount, dataCount);
580 /* now copy the parms and data */
581 if ( parmCount != 0 )
583 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
585 if ( dataCount != 0 ) {
586 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
589 /* account for new bytes */
590 asp->curData += dataCount;
591 asp->curParms += parmCount;
593 /* finally, if we're done, remove the packet from the queue and dispatch it */
594 if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
595 /* we've received it all */
596 lock_ObtainWrite(&smb_globalLock);
597 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
598 lock_ReleaseWrite(&smb_globalLock);
600 /* now dispatch it */
601 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
602 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
603 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
604 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
607 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
608 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
609 code = CM_ERROR_BADOP;
612 /* if an error is returned, we're supposed to send an error packet,
613 * otherwise the dispatched function already did the data sending.
614 * We give dispatched proc the responsibility since it knows how much
618 smb_SendTran2Error(vcp, asp, outp, code);
621 /* free the input tran 2 packet */
622 lock_ObtainWrite(&smb_globalLock);
623 smb_FreeTran2Packet(asp);
624 lock_ReleaseWrite(&smb_globalLock);
626 else if (firstPacket) {
627 /* the first packet in a multi-packet request, we need to send an
628 * ack to get more data.
630 smb_SetSMBDataLength(outp, 0);
631 smb_SendPacket(vcp, outp);
637 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
640 smb_tran2Packet_t *outp;
645 cm_scache_t *dscp; /* dir we're dealing with */
646 cm_scache_t *scp; /* file we're creating */
658 int parmSlot; /* which parm we're dealing with */
667 extraInfo = (p->parmsp[0] & 1); /* return extra info */
668 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
670 openFun = p->parmsp[6]; /* open function */
671 excl = ((openFun & 3) == 0);
672 trunc = ((openFun & 3) == 2); /* truncate it */
673 openMode = (p->parmsp[1] & 0x7);
674 openAction = 0; /* tracks what we did */
676 attributes = p->parmsp[3];
677 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
679 /* compute initial mode bits based on read-only flag in attributes */
680 initialModeBits = 0666;
681 if (attributes & 1) initialModeBits &= ~0222;
683 pathp = (char *) (&p->parmsp[14]);
685 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
687 spacep = cm_GetSpace();
688 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
690 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
691 /* special case magic file name for receiving IOCTL requests
692 * (since IOCTL calls themselves aren't getting through).
694 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
695 smb_SetupIoctlFid(fidp, spacep);
697 /* copy out remainder of the parms */
699 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
701 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
702 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
703 outp->parmsp[parmSlot] = 0; parmSlot++;
704 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
705 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
706 outp->parmsp[parmSlot] = openMode; parmSlot++;
707 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
708 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
710 /* and the final "always present" stuff */
711 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
712 /* next write out the "unique" ID */
713 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
714 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
715 outp->parmsp[parmSlot] = 0; parmSlot++;
716 if (returnEALength) {
717 outp->parmsp[parmSlot] = 0; parmSlot++;
718 outp->parmsp[parmSlot] = 0; parmSlot++;
722 outp->totalParms = parmSlot * 2;
724 smb_SendTran2Packet(vcp, outp, op);
726 smb_FreeTran2Packet(outp);
728 /* and clean up fid reference */
729 smb_ReleaseFID(fidp);
736 asciip = (lastNamep ? lastNamep : pathp);
737 hexp = osi_HexifyString( asciip );
738 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
743 userp = smb_GetTran2User(vcp, p);
744 /* In the off chance that userp is NULL, we log and abandon */
746 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
747 smb_FreeTran2Packet(outp);
748 return CM_ERROR_BADSMB;
751 tidPathp = smb_GetTIDPath(vcp, p->tid);
754 code = cm_NameI(cm_rootSCachep, pathp,
755 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
756 userp, tidPathp, &req, &scp);
758 code = cm_NameI(cm_rootSCachep, spacep->data,
759 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
760 userp, tidPathp, &req, &dscp);
761 cm_FreeSpace(spacep);
764 cm_ReleaseUser(userp);
765 smb_FreeTran2Packet(outp);
769 /* otherwise, scp points to the parent directory. Do a lookup,
770 * and truncate the file if we find it, otherwise we create the
773 if (!lastNamep) lastNamep = pathp;
775 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
777 if (code && code != CM_ERROR_NOSUCHFILE) {
778 cm_ReleaseSCache(dscp);
779 cm_ReleaseUser(userp);
780 smb_FreeTran2Packet(outp);
785 cm_FreeSpace(spacep);
788 /* if we get here, if code is 0, the file exists and is represented by
789 * scp. Otherwise, we have to create it.
792 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
794 if (dscp) cm_ReleaseSCache(dscp);
795 cm_ReleaseSCache(scp);
796 cm_ReleaseUser(userp);
797 smb_FreeTran2Packet(outp);
802 /* oops, file shouldn't be there */
803 if (dscp) cm_ReleaseSCache(dscp);
804 cm_ReleaseSCache(scp);
805 cm_ReleaseUser(userp);
806 smb_FreeTran2Packet(outp);
807 return CM_ERROR_EXISTS;
811 setAttr.mask = CM_ATTRMASK_LENGTH;
812 setAttr.length.LowPart = 0;
813 setAttr.length.HighPart = 0;
814 code = cm_SetAttr(scp, &setAttr, userp, &req);
815 openAction = 3; /* truncated existing file */
817 else openAction = 1; /* found existing file */
819 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
820 /* don't create if not found */
821 if (dscp) cm_ReleaseSCache(dscp);
822 osi_assert(scp == NULL);
823 cm_ReleaseUser(userp);
824 smb_FreeTran2Packet(outp);
825 return CM_ERROR_NOSUCHFILE;
828 osi_assert(dscp != NULL && scp == NULL);
829 openAction = 2; /* created file */
830 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
831 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
832 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
834 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
835 smb_NotifyChange(FILE_ACTION_ADDED,
836 FILE_NOTIFY_CHANGE_FILE_NAME,
837 dscp, lastNamep, NULL, TRUE);
838 if (!excl && code == CM_ERROR_EXISTS) {
839 /* not an exclusive create, and someone else tried
840 * creating it already, then we open it anyway. We
841 * don't bother retrying after this, since if this next
842 * fails, that means that the file was deleted after we
845 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
849 setAttr.mask = CM_ATTRMASK_LENGTH;
850 setAttr.length.LowPart = 0;
851 setAttr.length.HighPart = 0;
852 code = cm_SetAttr(scp, &setAttr, userp,
855 } /* lookup succeeded */
859 /* we don't need this any longer */
860 if (dscp) cm_ReleaseSCache(dscp);
863 /* something went wrong creating or truncating the file */
864 if (scp) cm_ReleaseSCache(scp);
865 cm_ReleaseUser(userp);
866 smb_FreeTran2Packet(outp);
870 /* make sure we're about to open a file */
871 if (scp->fileType != CM_SCACHETYPE_FILE) {
872 cm_ReleaseSCache(scp);
873 cm_ReleaseUser(userp);
874 smb_FreeTran2Packet(outp);
875 return CM_ERROR_ISDIR;
878 /* now all we have to do is open the file itself */
879 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
882 /* save a pointer to the vnode */
885 /* compute open mode */
886 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
887 if (openMode == 1 || openMode == 2)
888 fidp->flags |= SMB_FID_OPENWRITE;
890 smb_ReleaseFID(fidp);
892 cm_Open(scp, 0, userp);
894 /* copy out remainder of the parms */
896 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
897 lock_ObtainMutex(&scp->mx);
899 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
900 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
901 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
902 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
903 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
905 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
907 outp->parmsp[parmSlot] = openMode; parmSlot++;
908 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
909 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
911 /* and the final "always present" stuff */
912 outp->parmsp[parmSlot] = openAction; parmSlot++;
913 /* next write out the "unique" ID */
914 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
915 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
916 outp->parmsp[parmSlot] = 0; parmSlot++;
917 if (returnEALength) {
918 outp->parmsp[parmSlot] = 0; parmSlot++;
919 outp->parmsp[parmSlot] = 0; parmSlot++;
921 lock_ReleaseMutex(&scp->mx);
922 outp->totalData = 0; /* total # of data bytes */
923 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
925 smb_SendTran2Packet(vcp, outp, op);
927 smb_FreeTran2Packet(outp);
929 cm_ReleaseUser(userp);
930 /* leave scp held since we put it in fidp->scp */
934 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
936 return CM_ERROR_BADOP;
939 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
941 return CM_ERROR_BADOP;
944 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
946 smb_tran2Packet_t *outp;
947 smb_tran2QFSInfo_t qi;
950 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
952 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
954 switch (p->parmsp[0]) {
955 case 1: responseSize = sizeof(qi.u.allocInfo); break;
956 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
957 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
958 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
959 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
960 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
961 default: return CM_ERROR_INVAL;
964 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
965 switch (p->parmsp[0]) {
968 qi.u.allocInfo.FSID = 0;
969 qi.u.allocInfo.sectorsPerAllocUnit = 1;
970 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
971 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
972 qi.u.allocInfo.bytesPerSector = 1024;
977 qi.u.volumeInfo.vsn = 1234;
978 qi.u.volumeInfo.vnCount = 4;
979 /* we're supposed to pad it out with zeroes to the end */
980 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
981 memcpy(qi.u.volumeInfo.label, "AFS", 4);
986 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
987 qi.u.FSvolumeInfo.vsn = 1234;
988 qi.u.FSvolumeInfo.vnCount = 8;
989 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
995 temp.LowPart = 0x7fffffff;
996 qi.u.FSsizeInfo.totalAllocUnits = temp;
997 temp.LowPart = 0x3fffffff;
998 qi.u.FSsizeInfo.availAllocUnits = temp;
999 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
1000 qi.u.FSsizeInfo.bytesPerSector = 1024;
1004 /* FS device info */
1005 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
1006 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
1010 /* FS attribute info */
1011 /* attributes, defined in WINNT.H:
1012 * FILE_CASE_SENSITIVE_SEARCH 0x1
1013 * FILE_CASE_PRESERVED_NAMES 0x2
1014 * <no name defined> 0x4000
1015 * If bit 0x4000 is not set, Windows 95 thinks
1016 * we can't handle long (non-8.3) names,
1017 * despite our protestations to the contrary.
1019 qi.u.FSattributeInfo.attributes = 0x4003;
1020 qi.u.FSattributeInfo.maxCompLength = 255;
1021 qi.u.FSattributeInfo.FSnameLength = 6;
1022 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
1026 /* copy out return data, and set corresponding sizes */
1027 outp->totalParms = 0;
1028 outp->totalData = responseSize;
1029 memcpy(outp->datap, &qi, responseSize);
1031 /* send and free the packets */
1032 smb_SendTran2Packet(vcp, outp, op);
1033 smb_FreeTran2Packet(outp);
1038 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1040 return CM_ERROR_BADOP;
1043 struct smb_ShortNameRock {
1047 size_t shortNameLen;
1050 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
1053 struct smb_ShortNameRock *rockp;
1057 /* compare both names and vnodes, though probably just comparing vnodes
1058 * would be safe enough.
1060 if (cm_stricmp(dep->name, rockp->maskp) != 0)
1062 if (ntohl(dep->fid.vnode) != rockp->vnode)
1064 /* This is the entry */
1065 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1066 rockp->shortNameLen = shortNameEnd - rockp->shortName;
1067 return CM_ERROR_STOPNOW;
1070 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1071 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1073 struct smb_ShortNameRock rock;
1077 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1081 spacep = cm_GetSpace();
1082 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1084 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1086 cm_FreeSpace(spacep);
1087 if (code) return code;
1089 if (!lastNamep) lastNamep = pathp;
1092 thyper.HighPart = 0;
1093 rock.shortName = shortName;
1095 rock.maskp = lastNamep;
1096 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1099 cm_ReleaseSCache(dscp);
1102 return CM_ERROR_NOSUCHFILE;
1103 if (code == CM_ERROR_STOPNOW) {
1104 *shortNameLenp = rock.shortNameLen;
1110 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1112 smb_tran2Packet_t *outp;
1113 unsigned long dosTime;
1115 unsigned short infoLevel;
1117 unsigned short attributes;
1118 unsigned long extAttributes;
1123 cm_scache_t *scp, *dscp;
1132 infoLevel = p->parmsp[0];
1133 if (infoLevel == 6) nbytesRequired = 0;
1134 else if (infoLevel == 1) nbytesRequired = 22;
1135 else if (infoLevel == 2) nbytesRequired = 26;
1136 else if (infoLevel == 0x101) nbytesRequired = 40;
1137 else if (infoLevel == 0x102) nbytesRequired = 24;
1138 else if (infoLevel == 0x103) nbytesRequired = 4;
1139 else if (infoLevel == 0x108) nbytesRequired = 30;
1141 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1142 p->opcode, infoLevel);
1143 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1146 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1147 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
1149 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1151 if (infoLevel > 0x100)
1152 outp->totalParms = 2;
1154 outp->totalParms = 0;
1155 outp->totalData = nbytesRequired;
1157 /* now, if we're at infoLevel 6, we're only being asked to check
1158 * the syntax, so we just OK things now. In particular, we're *not*
1159 * being asked to verify anything about the state of any parent dirs.
1161 if (infoLevel == 6) {
1162 smb_SendTran2Packet(vcp, outp, opx);
1163 smb_FreeTran2Packet(outp);
1167 userp = smb_GetTran2User(vcp, p);
1169 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
1170 smb_FreeTran2Packet(outp);
1171 return CM_ERROR_BADSMB;
1174 tidPathp = smb_GetTIDPath(vcp, p->tid);
1177 * XXX Strange hack XXX
1179 * As of Patch 7 (13 January 98), we are having the following problem:
1180 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1181 * requests to look up "desktop.ini" in all the subdirectories.
1182 * This can cause zillions of timeouts looking up non-existent cells
1183 * and volumes, especially in the top-level directory.
1185 * We have not found any way to avoid this or work around it except
1186 * to explicitly ignore the requests for mount points that haven't
1187 * yet been evaluated and for directories that haven't yet been
1190 if (infoLevel == 0x101) {
1191 spacep = cm_GetSpace();
1192 smb_StripLastComponent(spacep->data, &lastComp,
1193 (char *)(&p->parmsp[3]));
1194 /* Make sure that lastComp is not NULL */
1196 if (strcmp(lastComp, "\\desktop.ini") == 0) {
1197 code = cm_NameI(cm_rootSCachep, spacep->data,
1201 userp, tidPathp, &req, &dscp);
1203 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1204 && !dscp->mountRootFidp)
1205 code = CM_ERROR_NOSUCHFILE;
1206 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1207 cm_buf_t *bp = buf_Find(dscp, &hzero);
1211 code = CM_ERROR_NOSUCHFILE;
1213 cm_ReleaseSCache(dscp);
1215 cm_FreeSpace(spacep);
1216 cm_ReleaseUser(userp);
1217 smb_SendTran2Error(vcp, p, opx, code);
1218 smb_FreeTran2Packet(outp);
1224 cm_FreeSpace(spacep);
1227 /* now do namei and stat, and copy out the info */
1228 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1229 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1232 cm_ReleaseUser(userp);
1233 smb_SendTran2Error(vcp, p, opx, code);
1234 smb_FreeTran2Packet(outp);
1238 lock_ObtainMutex(&scp->mx);
1239 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1240 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1241 if (code) goto done;
1243 /* now we have the status in the cache entry, and everything is locked.
1244 * Marshall the output data.
1247 /* for info level 108, figure out short name */
1248 if (infoLevel == 0x108) {
1249 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1250 tidPathp, scp->fid.vnode, shortName,
1257 *((u_long *)op) = len * 2; op += 4;
1258 mbstowcs((unsigned short *)op, shortName, len);
1263 if (infoLevel == 1 || infoLevel == 2) {
1264 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1265 *((u_long *)op) = dosTime; op += 4; /* creation time */
1266 *((u_long *)op) = dosTime; op += 4; /* access time */
1267 *((u_long *)op) = dosTime; op += 4; /* write time */
1268 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1269 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1270 attributes = smb_Attributes(scp);
1271 *((u_short *)op) = attributes; op += 2; /* attributes */
1273 else if (infoLevel == 0x101) {
1274 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1275 *((FILETIME *)op) = ft; op += 8; /* creation time */
1276 *((FILETIME *)op) = ft; op += 8; /* last access time */
1277 *((FILETIME *)op) = ft; op += 8; /* last write time */
1278 *((FILETIME *)op) = ft; op += 8; /* last change time */
1279 extAttributes = smb_ExtAttributes(scp);
1280 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1281 *((u_long *)op) = 0; op += 4; /* don't know what this is */
1283 else if (infoLevel == 0x102) {
1284 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1285 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1286 *((u_long *)op) = scp->linkCount; op += 4;
1289 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1292 else if (infoLevel == 0x103) {
1293 memset(op, 0, 4); op += 4; /* EA size */
1296 /* now, if we are being asked about extended attrs, return a 0 size */
1297 if (infoLevel == 2) {
1298 *((u_long *)op) = 0; op += 4;
1302 /* send and free the packets */
1304 lock_ReleaseMutex(&scp->mx);
1305 cm_ReleaseSCache(scp);
1306 cm_ReleaseUser(userp);
1308 smb_SendTran2Packet(vcp, outp, opx);
1310 smb_SendTran2Error(vcp, p, opx, code);
1311 smb_FreeTran2Packet(outp);
1316 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1318 return CM_ERROR_BADOP;
1321 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1323 smb_tran2Packet_t *outp;
1325 unsigned long attributes;
1326 unsigned short infoLevel;
1339 fidp = smb_FindFID(vcp, fid, 0);
1342 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
1346 infoLevel = p->parmsp[1];
1347 if (infoLevel == 0x101) nbytesRequired = 40;
1348 else if (infoLevel == 0x102) nbytesRequired = 24;
1349 else if (infoLevel == 0x103) nbytesRequired = 4;
1350 else if (infoLevel == 0x104) nbytesRequired = 6;
1352 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1353 p->opcode, infoLevel);
1354 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1355 smb_ReleaseFID(fidp);
1358 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1360 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1362 if (infoLevel > 0x100)
1363 outp->totalParms = 2;
1365 outp->totalParms = 0;
1366 outp->totalData = nbytesRequired;
1368 userp = smb_GetTran2User(vcp, p);
1370 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
1371 code = CM_ERROR_BADSMB;
1376 lock_ObtainMutex(&scp->mx);
1377 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1378 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1379 if (code) goto done;
1381 /* now we have the status in the cache entry, and everything is locked.
1382 * Marshall the output data.
1385 if (infoLevel == 0x101) {
1386 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1387 *((FILETIME *)op) = ft; op += 8; /* creation time */
1388 *((FILETIME *)op) = ft; op += 8; /* last access time */
1389 *((FILETIME *)op) = ft; op += 8; /* last write time */
1390 *((FILETIME *)op) = ft; op += 8; /* last change time */
1391 attributes = smb_ExtAttributes(scp);
1392 *((u_long *)op) = attributes; op += 4;
1393 *((u_long *)op) = 0; op += 4;
1395 else if (infoLevel == 0x102) {
1396 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1397 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1398 *((u_long *)op) = scp->linkCount; op += 4;
1399 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1400 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1404 else if (infoLevel == 0x103) {
1405 *((u_long *)op) = 0; op += 4;
1407 else if (infoLevel == 0x104) {
1411 if (fidp->NTopen_wholepathp)
1412 name = fidp->NTopen_wholepathp;
1414 name = "\\"; /* probably can't happen */
1416 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
1417 *((u_long *)op) = len * 2; op += 4;
1418 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1421 /* send and free the packets */
1423 lock_ReleaseMutex(&scp->mx);
1424 cm_ReleaseUser(userp);
1425 smb_ReleaseFID(fidp);
1426 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1427 else smb_SendTran2Error(vcp, p, opx, code);
1428 smb_FreeTran2Packet(outp);
1433 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1438 unsigned short infoLevel;
1439 smb_tran2Packet_t *outp;
1447 fidp = smb_FindFID(vcp, fid, 0);
1450 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1454 infoLevel = p->parmsp[1];
1455 if (infoLevel > 0x104 || infoLevel < 0x101) {
1456 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1457 p->opcode, infoLevel);
1458 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1459 smb_ReleaseFID(fidp);
1463 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1464 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1465 smb_ReleaseFID(fidp);
1468 if ((infoLevel == 0x103 || infoLevel == 0x104)
1469 && !(fidp->flags & SMB_FID_OPENWRITE)) {
1470 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1471 smb_ReleaseFID(fidp);
1475 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
1477 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1479 outp->totalParms = 2;
1480 outp->totalData = 0;
1482 userp = smb_GetTran2User(vcp, p);
1484 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
1485 code = CM_ERROR_BADSMB;
1491 if (infoLevel == 0x101) {
1493 unsigned int attribute;
1496 /* lock the vnode with a callback; we need the current status
1497 * to determine what the new status is, in some cases.
1499 lock_ObtainMutex(&scp->mx);
1500 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1501 CM_SCACHESYNC_GETSTATUS
1502 | CM_SCACHESYNC_NEEDCALLBACK);
1504 lock_ReleaseMutex(&scp->mx);
1508 /* prepare for setattr call */
1511 lastMod = *((FILETIME *)(p->datap + 16));
1512 /* when called as result of move a b, lastMod is (-1, -1).
1513 * If the check for -1 is not present, timestamp
1514 * of the resulting file will be 1969 (-1)
1516 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
1517 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
1518 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1519 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1521 fidp->flags |= SMB_FID_MTIMESETDONE;
1524 attribute = *((u_long *)(p->datap + 32));
1525 if (attribute != 0) {
1526 if ((scp->unixModeBits & 0222)
1527 && (attribute & 1) != 0) {
1528 /* make a writable file read-only */
1529 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1530 attr.unixModeBits = scp->unixModeBits & ~0222;
1532 else if ((scp->unixModeBits & 0222) == 0
1533 && (attribute & 1) == 0) {
1534 /* make a read-only file writable */
1535 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1536 attr.unixModeBits = scp->unixModeBits | 0222;
1539 lock_ReleaseMutex(&scp->mx);
1543 code = cm_SetAttr(scp, &attr, userp, &req);
1547 else if (infoLevel == 0x103 || infoLevel == 0x104) {
1548 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1551 attr.mask = CM_ATTRMASK_LENGTH;
1552 attr.length.LowPart = size.LowPart;
1553 attr.length.HighPart = size.HighPart;
1554 code = cm_SetAttr(scp, &attr, userp, &req);
1556 else if (infoLevel == 0x102) {
1557 if (*((char *)(p->datap))) {
1558 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1561 fidp->flags |= SMB_FID_DELONCLOSE;
1565 fidp->flags &= ~SMB_FID_DELONCLOSE;
1569 cm_ReleaseUser(userp);
1570 smb_ReleaseFID(fidp);
1571 if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1572 else smb_SendTran2Error(vcp, p, op, code);
1573 smb_FreeTran2Packet(outp);
1578 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1580 return CM_ERROR_BADOP;
1583 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1585 return CM_ERROR_BADOP;
1588 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1590 return CM_ERROR_BADOP;
1593 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1595 return CM_ERROR_BADOP;
1598 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1600 return CM_ERROR_BADOP;
1603 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1604 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1609 cm_scache_t *targetScp; /* target if scp is a symlink */
1614 unsigned short attr;
1615 unsigned long lattr;
1616 smb_dirListPatch_t *patchp;
1617 smb_dirListPatch_t *npatchp;
1619 for(patchp = *dirPatchespp; patchp; patchp =
1620 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1621 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1623 lock_ObtainMutex(&scp->mx);
1624 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1625 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1627 lock_ReleaseMutex(&scp->mx);
1628 cm_ReleaseSCache(scp);
1632 /* now watch for a symlink */
1633 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1634 lock_ReleaseMutex(&scp->mx);
1635 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
1637 /* we have a more accurate file to use (the
1638 * target of the symbolic link). Otherwise,
1639 * we'll just use the symlink anyway.
1641 osi_Log2(smb_logp, "symlink vp %x to vp %x",
1643 cm_ReleaseSCache(scp);
1646 lock_ObtainMutex(&scp->mx);
1649 dptr = patchp->dptr;
1651 if (infoLevel >= 0x101) {
1653 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1655 /* copy to Creation Time */
1656 *((FILETIME *)dptr) = ft;
1659 /* copy to Last Access Time */
1660 *((FILETIME *)dptr) = ft;
1663 /* copy to Last Write Time */
1664 *((FILETIME *)dptr) = ft;
1667 /* copy to Change Time */
1668 *((FILETIME *)dptr) = ft;
1671 /* Use length for both file length and alloc length */
1672 *((LARGE_INTEGER *)dptr) = scp->length;
1674 *((LARGE_INTEGER *)dptr) = scp->length;
1677 /* Copy attributes */
1678 lattr = smb_ExtAttributes(scp);
1679 /* merge in hidden (dot file) attribute */
1680 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1681 lattr |= SMB_ATTR_HIDDEN;
1682 *((u_long *)dptr) = lattr;
1687 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1689 /* and copy out date */
1690 shortTemp = (dosTime>>16) & 0xffff;
1691 *((u_short *)dptr) = shortTemp;
1694 /* copy out creation time */
1695 shortTemp = dosTime & 0xffff;
1696 *((u_short *)dptr) = shortTemp;
1699 /* and copy out date */
1700 shortTemp = (dosTime>>16) & 0xffff;
1701 *((u_short *)dptr) = shortTemp;
1704 /* copy out access time */
1705 shortTemp = dosTime & 0xffff;
1706 *((u_short *)dptr) = shortTemp;
1709 /* and copy out date */
1710 shortTemp = (dosTime>>16) & 0xffff;
1711 *((u_short *)dptr) = shortTemp;
1714 /* copy out mod time */
1715 shortTemp = dosTime & 0xffff;
1716 *((u_short *)dptr) = shortTemp;
1719 /* copy out file length and alloc length,
1720 * using the same for both
1722 *((u_long *)dptr) = scp->length.LowPart;
1724 *((u_long *)dptr) = scp->length.LowPart;
1727 /* finally copy out attributes as short */
1728 attr = smb_Attributes(scp);
1729 /* merge in hidden (dot file) attribute */
1730 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1731 attr |= SMB_ATTR_HIDDEN;
1732 *dptr++ = attr & 0xff;
1733 *dptr++ = (attr >> 8) & 0xff;
1736 lock_ReleaseMutex(&scp->mx);
1737 cm_ReleaseSCache(scp);
1740 /* now free the patches */
1741 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1742 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1746 /* and mark the list as empty */
1747 *dirPatchespp = NULL;
1752 #ifndef USE_OLD_MATCHING
1753 // char table for case insensitive comparison
1754 char mapCaseTable[256];
1756 VOID initUpperCaseTable(VOID)
1759 for (i = 0; i < 256; ++i)
1760 mapCaseTable[i] = toupper(i);
1761 // make '"' match '.'
1762 mapCaseTable[(int)'"'] = toupper('.');
1765 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
1767 // Note : this procedure works recursively calling itself.
1769 // PSZ pattern : string containing metacharacters.
1770 // PSZ name : file name to be compared with 'pattern'.
1772 // BOOL : TRUE/FALSE (match/mistmatch)
1774 BOOL szWildCardMatchFileName(PSZ pattern, PSZ name) {
1775 PSZ pename; // points to the last 'name' character
1777 pename = name + strlen(name) - 1;
1781 if (*(++pattern) != '<' || *(++pattern) != '*') {
1782 if (*name == '.') return FALSE;
1788 while ((*pattern == '<') || (*pattern == '*') || (*pattern == '?')) ++pattern;
1789 if (!*pattern) return TRUE;
1790 for (p = pename; p >= name; --p) {
1791 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
1792 szWildCardMatchFileName(pattern + 1, p + 1))
1797 if (mapCaseTable[*name] != mapCaseTable[*pattern]) return FALSE;
1801 } /* endwhile */ return !*pattern;
1804 /* do a case-folding search of the star name mask with the name in namep.
1805 * Return 1 if we match, otherwise 0.
1807 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1809 /* make sure we only match 8.3 names, if requested */
1810 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
1813 return szWildCardMatchFileName(maskp, namep) ? 1:0;
1816 #else /* USE_OLD_MATCHING */
1817 /* do a case-folding search of the star name mask with the name in namep.
1818 * Return 1 if we match, otherwise 0.
1820 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1822 unsigned char tcp1, tcp2; /* Pattern characters */
1823 unsigned char tcn1; /* Name characters */
1824 int sawDot = 0, sawStar = 0, req8dot3 = 0;
1825 char *starNamep, *starMaskp;
1826 static char nullCharp[] = {0};
1827 int casefold = flags & CM_FLAG_CASEFOLD;
1829 /* make sure we only match 8.3 names, if requested */
1830 req8dot3 = (flags & CM_FLAG_8DOT3);
1831 if (req8dot3 && !cm_Is8Dot3(namep))
1836 /* Next pattern character */
1839 /* Next name character */
1843 /* 0 - end of pattern */
1849 else if (tcp1 == '.' || tcp1 == '"') {
1859 * first dot in pattern;
1860 * must match dot or end of name
1865 else if (tcn1 == '.') {
1874 else if (tcp1 == '?') {
1875 if (tcn1 == 0 || tcn1 == '.')
1880 else if (tcp1 == '>') {
1881 if (tcn1 != 0 && tcn1 != '.')
1885 else if (tcp1 == '*' || tcp1 == '<') {
1889 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
1890 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
1905 * pattern character after '*' is not null or
1906 * period. If it is '?' or '>', we are not
1907 * going to understand it. If it is '*' or
1908 * '<', we are going to skip over it. None of
1909 * these are likely, I hope.
1911 /* skip over '*' and '<' */
1912 while (tcp2 == '*' || tcp2 == '<')
1915 /* skip over characters that don't match tcp2 */
1916 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
1917 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
1918 (!casefold && tcn1 != tcp2)))
1922 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
1925 /* Remember where we are */
1935 /* tcp1 is not a wildcard */
1936 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
1937 (!casefold && tcn1 == tcp1)) {
1942 /* if trying to match a star pattern, go back */
1944 maskp = starMaskp - 2;
1945 namep = starNamep + 1;
1954 #endif /* USE_OLD_MATCHING */
1956 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1965 smb_dirListPatch_t *dirListPatchesp;
1966 smb_dirListPatch_t *curPatchp;
1969 long orbytes; /* # of bytes in this output record */
1970 long ohbytes; /* # of bytes, except file name */
1971 long onbytes; /* # of bytes in name, incl. term. null */
1972 osi_hyper_t dirLength;
1973 osi_hyper_t bufferOffset;
1974 osi_hyper_t curOffset;
1976 smb_dirSearch_t *dsp;
1980 cm_pageHeader_t *pageHeaderp;
1981 cm_user_t *userp = NULL;
1984 long nextEntryCookie;
1985 int numDirChunks; /* # of 32 byte dir chunks in this entry */
1986 char *op; /* output data ptr */
1987 char *origOp; /* original value of op */
1988 cm_space_t *spacep; /* for pathname buffer */
1989 long maxReturnData; /* max # of return data */
1990 long maxReturnParms; /* max # of return parms */
1991 long bytesInBuffer; /* # data bytes in the output buffer */
1993 char *maskp; /* mask part of path */
1997 smb_tran2Packet_t *outp; /* response packet */
2000 char shortName[13]; /* 8.3 name if needed */
2012 if (p->opcode == 1) {
2013 /* find first; obtain basic parameters from request */
2014 attribute = p->parmsp[0];
2015 maxCount = p->parmsp[1];
2016 infoLevel = p->parmsp[3];
2017 searchFlags = p->parmsp[2];
2018 dsp = smb_NewDirSearch(1);
2019 dsp->attribute = attribute;
2020 pathp = ((char *) p->parmsp) + 12; /* points to path */
2022 maskp = strrchr(pathp, '\\');
2023 if (maskp == NULL) maskp = pathp;
2024 else maskp++; /* skip over backslash */
2025 strcpy(dsp->mask, maskp); /* and save mask */
2026 /* track if this is likely to match a lot of entries */
2027 starPattern = smb_V3IsStarMask(maskp);
2030 osi_assert(p->opcode == 2);
2031 /* find next; obtain basic parameters from request or open dir file */
2032 dsp = smb_FindDirSearch(p->parmsp[0]);
2033 if (!dsp) return CM_ERROR_BADFD;
2034 attribute = dsp->attribute;
2035 maxCount = p->parmsp[1];
2036 infoLevel = p->parmsp[2];
2037 searchFlags = p->parmsp[5];
2039 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
2041 starPattern = 1; /* assume, since required a Find Next */
2045 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
2046 attribute, infoLevel, maxCount, searchFlags);
2048 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
2049 p->opcode, nextCookie);
2051 if (infoLevel >= 0x101)
2052 searchFlags &= ~4; /* no resume keys */
2054 dirListPatchesp = NULL;
2056 maxReturnData = p->maxReturnData;
2057 if (p->opcode == 1) /* find first */
2058 maxReturnParms = 10; /* bytes */
2060 maxReturnParms = 8; /* bytes */
2062 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
2063 if (maxReturnData > 6000)
2064 maxReturnData = 6000;
2065 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
2067 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
2070 osi_Log1(smb_logp, "T2 receive search dir %s",
2071 osi_LogSaveString(smb_logp, pathp));
2073 /* bail out if request looks bad */
2074 if (p->opcode == 1 && !pathp) {
2075 smb_ReleaseDirSearch(dsp);
2076 smb_FreeTran2Packet(outp);
2077 return CM_ERROR_BADSMB;
2080 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
2081 nextCookie, dsp->cookie);
2083 userp = smb_GetTran2User(vcp, p);
2085 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
2086 smb_ReleaseDirSearch(dsp);
2087 smb_FreeTran2Packet(outp);
2088 return CM_ERROR_BADSMB;
2091 /* try to get the vnode for the path name next */
2092 lock_ObtainMutex(&dsp->mx);
2099 spacep = cm_GetSpace();
2100 smb_StripLastComponent(spacep->data, NULL, pathp);
2101 lock_ReleaseMutex(&dsp->mx);
2103 tidPathp = smb_GetTIDPath(vcp, p->tid);
2104 code = cm_NameI(cm_rootSCachep, spacep->data,
2105 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2106 userp, tidPathp, &req, &scp);
2107 cm_FreeSpace(spacep);
2109 lock_ObtainMutex(&dsp->mx);
2111 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2113 /* we need one hold for the entry we just stored into,
2114 * and one for our own processing. When we're done
2115 * with this function, we'll drop the one for our own
2116 * processing. We held it once from the namei call,
2117 * and so we do another hold now.
2120 lock_ObtainMutex(&scp->mx);
2121 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2122 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2123 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2124 dsp->flags |= SMB_DIRSEARCH_BULKST;
2126 lock_ReleaseMutex(&scp->mx);
2129 lock_ReleaseMutex(&dsp->mx);
2131 cm_ReleaseUser(userp);
2132 smb_FreeTran2Packet(outp);
2133 smb_DeleteDirSearch(dsp);
2134 smb_ReleaseDirSearch(dsp);
2138 /* get the directory size */
2139 lock_ObtainMutex(&scp->mx);
2140 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2141 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2143 lock_ReleaseMutex(&scp->mx);
2144 cm_ReleaseSCache(scp);
2145 cm_ReleaseUser(userp);
2146 smb_FreeTran2Packet(outp);
2147 smb_DeleteDirSearch(dsp);
2148 smb_ReleaseDirSearch(dsp);
2153 dirLength = scp->length;
2155 bufferOffset.LowPart = bufferOffset.HighPart = 0;
2156 curOffset.HighPart = 0;
2157 curOffset.LowPart = nextCookie;
2158 origOp = outp->datap;
2166 if (searchFlags & 4)
2167 /* skip over resume key */
2170 /* make sure that curOffset.LowPart doesn't point to the first
2171 * 32 bytes in the 2nd through last dir page, and that it doesn't
2172 * point at the first 13 32-byte chunks in the first dir page,
2173 * since those are dir and page headers, and don't contain useful
2176 temp = curOffset.LowPart & (2048-1);
2177 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2178 /* we're in the first page */
2179 if (temp < 13*32) temp = 13*32;
2182 /* we're in a later dir page */
2183 if (temp < 32) temp = 32;
2186 /* make sure the low order 5 bits are zero */
2189 /* now put temp bits back ito curOffset.LowPart */
2190 curOffset.LowPart &= ~(2048-1);
2191 curOffset.LowPart |= temp;
2193 /* check if we've passed the dir's EOF */
2194 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2199 /* check if we've returned all the names that will fit in the
2200 * response packet; we check return count as well as the number
2201 * of bytes requested. We check the # of bytes after we find
2202 * the dir entry, since we'll need to check its size.
2204 if (returnedNames >= maxCount) {
2208 /* see if we can use the bufferp we have now; compute in which
2209 * page the current offset would be, and check whether that's
2210 * the offset of the buffer we have. If not, get the buffer.
2212 thyper.HighPart = curOffset.HighPart;
2213 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2214 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2217 buf_Release(bufferp);
2220 lock_ReleaseMutex(&scp->mx);
2221 lock_ObtainRead(&scp->bufCreateLock);
2222 code = buf_Get(scp, &thyper, &bufferp);
2223 lock_ReleaseRead(&scp->bufCreateLock);
2225 /* now, if we're doing a star match, do bulk fetching
2226 * of all of the status info for files in the dir.
2229 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2232 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2233 && LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
2234 /* Don't bulk stat if risking timeout */
2235 int now = GetCurrentTime();
2236 if (now - req.startTime > 5000) {
2237 scp->bulkStatProgress = thyper;
2238 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2239 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2241 cm_TryBulkStat(scp, &thyper, userp, &req);
2245 lock_ObtainMutex(&scp->mx);
2247 bufferOffset = thyper;
2249 /* now get the data in the cache */
2251 code = cm_SyncOp(scp, bufferp, userp, &req,
2253 CM_SCACHESYNC_NEEDCALLBACK
2254 | CM_SCACHESYNC_READ);
2257 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2259 /* otherwise, load the buffer and try again */
2260 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2265 buf_Release(bufferp);
2269 } /* if (wrong buffer) ... */
2271 /* now we have the buffer containing the entry we're interested
2272 * in; copy it out if it represents a non-deleted entry.
2274 entryInDir = curOffset.LowPart & (2048-1);
2275 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2277 /* page header will help tell us which entries are free. Page
2278 * header can change more often than once per buffer, since
2279 * AFS 3 dir page size may be less than (but not more than)
2280 * a buffer package buffer.
2282 /* only look intra-buffer */
2283 temp = curOffset.LowPart & (buf_bufferSize - 1);
2284 temp &= ~(2048 - 1); /* turn off intra-page bits */
2285 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2287 /* now determine which entry we're looking at in the page.
2288 * If it is free (there's a free bitmap at the start of the
2289 * dir), we should skip these 32 bytes.
2291 slotInPage = (entryInDir & 0x7e0) >> 5;
2292 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2293 & (1 << (slotInPage & 0x7)))) {
2294 /* this entry is free */
2295 numDirChunks = 1; /* only skip this guy */
2299 tp = bufferp->datap + entryInBuffer;
2300 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
2302 /* while we're here, compute the next entry's location, too,
2303 * since we'll need it when writing out the cookie into the dir
2306 * XXXX Probably should do more sanity checking.
2308 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2310 /* compute offset of cookie representing next entry */
2311 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
2313 /* Need 8.3 name? */
2315 if (infoLevel == 0x104
2316 && dep->fid.vnode != 0
2317 && !cm_Is8Dot3(dep->name)) {
2318 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2322 /* When matching, we are using doing a case fold if we have a wildcard mask.
2323 * If we get a non-wildcard match, it's a lookup for a specific file.
2325 if (dep->fid.vnode != 0 &&
2326 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0))
2328 && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
2330 /* Eliminate entries that don't match requested attributes */
2331 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
2332 smb_IsDotFile(dep->name))
2333 goto nextEntry; /* no hidden files */
2335 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
2337 /* We have already done the cm_TryBulkStat above */
2338 fid.cell = scp->fid.cell;
2339 fid.volume = scp->fid.volume;
2340 fid.vnode = ntohl(dep->fid.vnode);
2341 fid.unique = ntohl(dep->fid.unique);
2342 fileType = cm_FindFileType(&fid);
2343 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
2344 "has filetype %d", dep->name,
2346 if (fileType == CM_SCACHETYPE_DIRECTORY)
2350 /* finally check if this name will fit */
2352 /* standard dir entry stuff */
2353 if (infoLevel < 0x101)
2354 ohbytes = 23; /* pre-NT */
2355 else if (infoLevel == 0x103)
2356 ohbytes = 12; /* NT names only */
2358 ohbytes = 64; /* NT */
2360 if (infoLevel == 0x104)
2361 ohbytes += 26; /* Short name & length */
2363 if (searchFlags & 4) {
2364 ohbytes += 4; /* if resume key required */
2368 && infoLevel != 0x101
2369 && infoLevel != 0x103)
2370 ohbytes += 4; /* EASIZE */
2372 /* add header to name & term. null */
2373 orbytes = onbytes + ohbytes + 1;
2375 /* now, we round up the record to a 4 byte alignment,
2376 * and we make sure that we have enough room here for
2377 * even the aligned version (so we don't have to worry
2378 * about an * overflow when we pad things out below).
2379 * That's the reason for the alignment arithmetic below.
2381 if (infoLevel >= 0x101)
2382 align = (4 - (orbytes & 3)) & 3;
2385 if (orbytes + bytesInBuffer + align > maxReturnData)
2388 /* this is one of the entries to use: it is not deleted
2389 * and it matches the star pattern we're looking for.
2390 * Put out the name, preceded by its length.
2392 /* First zero everything else */
2393 memset(origOp, 0, ohbytes);
2395 if (infoLevel <= 0x101)
2396 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2397 else if (infoLevel == 0x103)
2398 *((u_long *)(op + 8)) = onbytes;
2400 *((u_long *)(op + 60)) = onbytes;
2401 strcpy(origOp+ohbytes, dep->name);
2403 /* Short name if requested and needed */
2404 if (infoLevel == 0x104) {
2405 if (NeedShortName) {
2406 strcpy(op + 70, shortName);
2407 *(op + 68) = shortNameEnd - shortName;
2411 /* now, adjust the # of entries copied */
2414 /* NextEntryOffset and FileIndex */
2415 if (infoLevel >= 101) {
2416 int entryOffset = orbytes + align;
2417 *((u_long *)op) = entryOffset;
2418 *((u_long *)(op+4)) = nextEntryCookie;
2421 /* now we emit the attribute. This is tricky, since
2422 * we need to really stat the file to find out what
2423 * type of entry we've got. Right now, we're copying
2424 * out data from * a buffer, while holding the scp
2425 * locked, so it isn't really convenient to stat
2426 * something now. We'll put in a place holder
2427 * now, and make a second pass before returning this
2428 * to get the real attributes. So, we just skip the
2429 * data for now, and adjust it later. We allocate a
2430 * patch record to make it easy to find this point
2431 * later. The replay will happen at a time when it is
2432 * safe to unlock the directory.
2434 if (infoLevel != 0x103) {
2435 curPatchp = malloc(sizeof(*curPatchp));
2436 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2438 curPatchp->dptr = op;
2439 if (infoLevel >= 0x101)
2440 curPatchp->dptr += 8;
2442 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
2443 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
2446 curPatchp->flags = 0;
2448 curPatchp->fid.cell = scp->fid.cell;
2449 curPatchp->fid.volume = scp->fid.volume;
2450 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2451 curPatchp->fid.unique = ntohl(dep->fid.unique);
2454 curPatchp->dep = dep;
2457 if (searchFlags & 4)
2458 /* put out resume key */
2459 *((u_long *)origOp) = nextEntryCookie;
2461 /* Adjust byte ptr and count */
2462 origOp += orbytes; /* skip entire record */
2463 bytesInBuffer += orbytes;
2465 /* and pad the record out */
2466 while (--align >= 0) {
2471 } /* if we're including this name */
2472 else if(!NeedShortName &&
2475 dep->fid.vnode != 0 &&
2476 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
2477 /* We were looking for exact matches, but here's an inexact one*/
2482 /* and adjust curOffset to be where the new cookie is */
2483 thyper.HighPart = 0;
2484 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2485 curOffset = LargeIntegerAdd(thyper, curOffset);
2486 } /* while copying data for dir listing */
2488 /* If we didn't get a star pattern, we did an exact match during the first pass.
2489 * If there were no exact matches found, we fail over to inexact matches by
2490 * marking the query as a star pattern (matches all case permutations), and
2491 * re-running the query.
2493 if (returnedNames == 0 && !starPattern && foundInexact) {
2494 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
2499 /* release the mutex */
2500 lock_ReleaseMutex(&scp->mx);
2501 if (bufferp) buf_Release(bufferp);
2503 /* apply and free last set of patches; if not doing a star match, this
2504 * will be empty, but better safe (and freeing everything) than sorry.
2506 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2509 /* now put out the final parameters */
2510 if (returnedNames == 0) eos = 1;
2511 if (p->opcode == 1) {
2513 outp->parmsp[0] = (unsigned short) dsp->cookie;
2514 outp->parmsp[1] = returnedNames;
2515 outp->parmsp[2] = eos;
2516 outp->parmsp[3] = 0; /* nothing wrong with EAS */
2517 outp->parmsp[4] = 0;
2518 /* don't need last name to continue
2519 * search, cookie is enough. Normally,
2520 * this is the offset of the file name
2521 * of the last entry returned.
2523 outp->totalParms = 10; /* in bytes */
2527 outp->parmsp[0] = returnedNames;
2528 outp->parmsp[1] = eos;
2529 outp->parmsp[2] = 0; /* EAS error */
2530 outp->parmsp[3] = 0; /* last name, as above */
2531 outp->totalParms = 8; /* in bytes */
2534 /* return # of bytes in the buffer */
2535 outp->totalData = bytesInBuffer;
2537 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
2538 returnedNames, code);
2540 /* Return error code if unsuccessful on first request */
2541 if (code == 0 && p->opcode == 1 && returnedNames == 0)
2542 code = CM_ERROR_NOSUCHFILE;
2544 /* if we're supposed to close the search after this request, or if
2545 * we're supposed to close the search if we're done, and we're done,
2546 * or if something went wrong, close the search.
2548 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2549 if ((searchFlags & 1) || (returnedNames == 0) ||
2550 ((searchFlags & 2) && eos) || code != 0)
2551 smb_DeleteDirSearch(dsp);
2553 smb_SendTran2Error(vcp, p, opx, code);
2555 smb_SendTran2Packet(vcp, outp, opx);
2557 smb_FreeTran2Packet(outp);
2558 smb_ReleaseDirSearch(dsp);
2559 cm_ReleaseSCache(scp);
2560 cm_ReleaseUser(userp);
2564 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2567 smb_dirSearch_t *dsp;
2569 dirHandle = smb_GetSMBParm(inp, 0);
2571 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
2573 dsp = smb_FindDirSearch(dirHandle);
2576 return CM_ERROR_BADFD;
2578 /* otherwise, we have an FD to destroy */
2579 smb_DeleteDirSearch(dsp);
2580 smb_ReleaseDirSearch(dsp);
2582 /* and return results */
2583 smb_SetSMBDataLength(outp, 0);
2588 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2590 smb_SetSMBDataLength(outp, 0);
2594 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2601 cm_scache_t *dscp; /* dir we're dealing with */
2602 cm_scache_t *scp; /* file we're creating */
2604 int initialModeBits;
2614 int parmSlot; /* which parm we're dealing with */
2622 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
2623 openFun = smb_GetSMBParm(inp, 8); /* open function */
2624 excl = ((openFun & 3) == 0);
2625 trunc = ((openFun & 3) == 2); /* truncate it */
2626 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2627 openAction = 0; /* tracks what we did */
2629 attributes = smb_GetSMBParm(inp, 5);
2630 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2632 /* compute initial mode bits based on read-only flag in attributes */
2633 initialModeBits = 0666;
2634 if (attributes & 1) initialModeBits &= ~0222;
2636 pathp = smb_GetSMBData(inp, NULL);
2638 spacep = inp->spacep;
2639 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2641 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2642 /* special case magic file name for receiving IOCTL requests
2643 * (since IOCTL calls themselves aren't getting through).
2646 osi_Log0(smb_logp, "IOCTL Open");
2649 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2650 smb_SetupIoctlFid(fidp, spacep);
2652 /* set inp->fid so that later read calls in same msg can find fid */
2653 inp->fid = fidp->fid;
2655 /* copy out remainder of the parms */
2657 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2659 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2660 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
2661 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2662 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
2663 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2664 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2665 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2666 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2668 /* and the final "always present" stuff */
2669 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2670 /* next write out the "unique" ID */
2671 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2672 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2673 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2674 smb_SetSMBDataLength(outp, 0);
2676 /* and clean up fid reference */
2677 smb_ReleaseFID(fidp);
2681 #ifdef DEBUG_VERBOSE
2683 char *hexp, *asciip;
2684 asciip = (lastNamep ? lastNamep : pathp );
2685 hexp = osi_HexifyString(asciip);
2686 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
2690 userp = smb_GetUser(vcp, inp);
2693 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2694 code = cm_NameI(cm_rootSCachep, pathp,
2695 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2696 userp, tidPathp, &req, &scp);
2698 code = cm_NameI(cm_rootSCachep, spacep->data,
2699 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2700 userp, tidPathp, &req, &dscp);
2703 cm_ReleaseUser(userp);
2707 /* otherwise, scp points to the parent directory. Do a lookup,
2708 * and truncate the file if we find it, otherwise we create the
2711 if (!lastNamep) lastNamep = pathp;
2713 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2715 if (code && code != CM_ERROR_NOSUCHFILE) {
2716 cm_ReleaseSCache(dscp);
2717 cm_ReleaseUser(userp);
2722 /* if we get here, if code is 0, the file exists and is represented by
2723 * scp. Otherwise, we have to create it. The dir may be represented
2724 * by dscp, or we may have found the file directly. If code is non-zero,
2728 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2730 if (dscp) cm_ReleaseSCache(dscp);
2731 cm_ReleaseSCache(scp);
2732 cm_ReleaseUser(userp);
2737 /* oops, file shouldn't be there */
2738 if (dscp) cm_ReleaseSCache(dscp);
2739 cm_ReleaseSCache(scp);
2740 cm_ReleaseUser(userp);
2741 return CM_ERROR_EXISTS;
2745 setAttr.mask = CM_ATTRMASK_LENGTH;
2746 setAttr.length.LowPart = 0;
2747 setAttr.length.HighPart = 0;
2748 code = cm_SetAttr(scp, &setAttr, userp, &req);
2749 openAction = 3; /* truncated existing file */
2751 else openAction = 1; /* found existing file */
2753 else if (!(openFun & 0x10)) {
2754 /* don't create if not found */
2755 if (dscp) cm_ReleaseSCache(dscp);
2756 cm_ReleaseUser(userp);
2757 return CM_ERROR_NOSUCHFILE;
2760 osi_assert(dscp != NULL);
2761 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
2762 osi_LogSaveString(smb_logp, lastNamep));
2763 openAction = 2; /* created file */
2764 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2765 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2766 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2768 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2769 smb_NotifyChange(FILE_ACTION_ADDED,
2770 FILE_NOTIFY_CHANGE_FILE_NAME,
2771 dscp, lastNamep, NULL, TRUE);
2772 if (!excl && code == CM_ERROR_EXISTS) {
2773 /* not an exclusive create, and someone else tried
2774 * creating it already, then we open it anyway. We
2775 * don't bother retrying after this, since if this next
2776 * fails, that means that the file was deleted after we
2777 * started this call.
2779 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2783 setAttr.mask = CM_ATTRMASK_LENGTH;
2784 setAttr.length.LowPart = 0;
2785 setAttr.length.HighPart = 0;
2786 code = cm_SetAttr(scp, &setAttr, userp, &req);
2788 } /* lookup succeeded */
2792 /* we don't need this any longer */
2793 if (dscp) cm_ReleaseSCache(dscp);
2796 /* something went wrong creating or truncating the file */
2797 if (scp) cm_ReleaseSCache(scp);
2798 cm_ReleaseUser(userp);
2802 /* make sure we're about to open a file */
2803 if (scp->fileType != CM_SCACHETYPE_FILE) {
2804 cm_ReleaseSCache(scp);
2805 cm_ReleaseUser(userp);
2806 return CM_ERROR_ISDIR;
2809 /* now all we have to do is open the file itself */
2810 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2813 /* save a pointer to the vnode */
2816 /* compute open mode */
2817 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2818 if (openMode == 1 || openMode == 2)
2819 fidp->flags |= SMB_FID_OPENWRITE;
2821 smb_ReleaseFID(fidp);
2823 cm_Open(scp, 0, userp);
2825 /* set inp->fid so that later read calls in same msg can find fid */
2826 inp->fid = fidp->fid;
2828 /* copy out remainder of the parms */
2830 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2831 lock_ObtainMutex(&scp->mx);
2833 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2834 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2835 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2836 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2837 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2838 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2839 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2840 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2841 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2843 /* and the final "always present" stuff */
2844 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2845 /* next write out the "unique" ID */
2846 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2847 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2848 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2849 lock_ReleaseMutex(&scp->mx);
2850 smb_SetSMBDataLength(outp, 0);
2852 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
2854 cm_ReleaseUser(userp);
2855 /* leave scp held since we put it in fidp->scp */
2859 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2866 unsigned char LockType;
2867 unsigned short NumberOfUnlocks, NumberOfLocks;
2868 unsigned long Timeout;
2870 LARGE_INTEGER LOffset, LLength;
2871 smb_waitingLock_t *waitingLock;
2878 fid = smb_GetSMBParm(inp, 2);
2879 fid = smb_ChainFID(fid, inp);
2881 fidp = smb_FindFID(vcp, fid, 0);
2882 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2883 return CM_ERROR_BADFD;
2885 /* set inp->fid so that later read calls in same msg can find fid */
2888 userp = smb_GetUser(vcp, inp);
2892 lock_ObtainMutex(&scp->mx);
2893 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2894 CM_SCACHESYNC_NEEDCALLBACK
2895 | CM_SCACHESYNC_GETSTATUS
2896 | CM_SCACHESYNC_LOCK);
2897 if (code) goto doneSync;
2899 LockType = smb_GetSMBParm(inp, 3) & 0xff;
2900 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2901 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2902 NumberOfLocks = smb_GetSMBParm(inp, 7);
2904 op = smb_GetSMBData(inp, NULL);
2906 for (i=0; i<NumberOfUnlocks; i++) {
2907 if (LockType & 0x10) {
2909 LOffset.HighPart = *((LONG *)(op + 4));
2910 LOffset.LowPart = *((DWORD *)(op + 8));
2911 LLength.HighPart = *((LONG *)(op + 12));
2912 LLength.LowPart = *((DWORD *)(op + 16));
2916 /* Not Large Files */
2917 LOffset.HighPart = 0;
2918 LOffset.LowPart = *((DWORD *)(op + 2));
2919 LLength.HighPart = 0;
2920 LLength.LowPart = *((DWORD *)(op + 6));
2923 if (LargeIntegerNotEqualToZero(LOffset))
2925 /* Do not check length -- length check done in cm_Unlock */
2927 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2928 if (code) goto done;
2931 for (i=0; i<NumberOfLocks; i++) {
2932 if (LockType & 0x10) {
2934 LOffset.HighPart = *((LONG *)(op + 4));
2935 LOffset.LowPart = *((DWORD *)(op + 8));
2936 LLength.HighPart = *((LONG *)(op + 12));
2937 LLength.LowPart = *((DWORD *)(op + 16));
2941 /* Not Large Files */
2942 LOffset.HighPart = 0;
2943 LOffset.LowPart = *((DWORD *)(op + 2));
2944 LLength.HighPart = 0;
2945 LLength.LowPart = *((DWORD *)(op + 6));
2948 if (LargeIntegerNotEqualToZero(LOffset))
2950 if (LargeIntegerLessThan(LOffset, scp->length))
2953 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2954 userp, &req, &lockp);
2955 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2956 /* Put on waiting list */
2957 waitingLock = malloc(sizeof(smb_waitingLock_t));
2958 waitingLock->vcp = vcp;
2959 waitingLock->inp = smb_CopyPacket(inp);
2960 waitingLock->outp = smb_CopyPacket(outp);
2961 waitingLock->timeRemaining = Timeout;
2962 waitingLock->lockp = lockp;
2963 lock_ObtainWrite(&smb_globalLock);
2964 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2966 osi_Wakeup((long) &smb_allWaitingLocks);
2967 lock_ReleaseWrite(&smb_globalLock);
2968 /* don't send reply immediately */
2969 outp->flags |= SMB_PACKETFLAG_NOSEND;
2975 /* release any locks acquired before the failure */
2978 smb_SetSMBDataLength(outp, 0);
2980 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2982 lock_ReleaseMutex(&scp->mx);
2983 cm_ReleaseUser(userp);
2984 smb_ReleaseFID(fidp);
2989 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3001 fid = smb_GetSMBParm(inp, 0);
3002 fid = smb_ChainFID(fid, inp);
3004 fidp = smb_FindFID(vcp, fid, 0);
3005 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
3006 return CM_ERROR_BADFD;
3009 userp = smb_GetUser(vcp, inp);
3013 /* otherwise, stat the file */
3014 lock_ObtainMutex(&scp->mx);
3015 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3016 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3017 if (code) goto done;
3019 /* decode times. We need a search time, but the response to this
3020 * call provides the date first, not the time, as returned in the
3021 * searchTime variable. So we take the high-order bits first.
3023 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
3024 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
3025 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
3026 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
3027 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
3028 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
3029 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
3031 /* now handle file size and allocation size */
3032 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
3033 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
3034 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
3035 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
3037 /* file attribute */
3038 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
3040 /* and finalize stuff */
3041 smb_SetSMBDataLength(outp, 0);
3045 lock_ReleaseMutex(&scp->mx);
3046 cm_ReleaseUser(userp);
3047 smb_ReleaseFID(fidp);
3051 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3065 fid = smb_GetSMBParm(inp, 0);
3066 fid = smb_ChainFID(fid, inp);
3068 fidp = smb_FindFID(vcp, fid, 0);
3069 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
3070 return CM_ERROR_BADFD;
3073 userp = smb_GetUser(vcp, inp);
3077 /* now prepare to call cm_setattr. This message only sets various times,
3078 * and AFS only implements mtime, and we'll set the mtime if that's
3079 * requested. The others we'll ignore.
3081 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
3083 if (searchTime != 0) {
3084 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
3086 if ( unixTime != -1 ) {
3087 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
3088 attrs.clientModTime = unixTime;
3089 code = cm_SetAttr(scp, &attrs, userp, &req);
3091 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
3093 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
3098 cm_ReleaseUser(userp);
3099 smb_ReleaseFID(fidp);
3104 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3107 long count, finalCount;
3114 fd = smb_GetSMBParm(inp, 2);
3115 count = smb_GetSMBParm(inp, 5);
3116 offset.HighPart = 0; /* too bad */
3117 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
3119 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
3120 fd, offset.LowPart, count);
3122 fd = smb_ChainFID(fd, inp);
3123 fidp = smb_FindFID(vcp, fd, 0);
3125 return CM_ERROR_BADFD;
3127 /* set inp->fid so that later read calls in same msg can find fid */
3130 if (fidp->flags & SMB_FID_IOCTL) {
3131 return smb_IoctlV3Read(fidp, vcp, inp, outp);
3134 userp = smb_GetUser(vcp, inp);
3136 /* 0 and 1 are reserved for request chaining, were setup by our caller,
3137 * and will be further filled in after we return.
3139 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
3140 smb_SetSMBParm(outp, 3, 0); /* resvd */
3141 smb_SetSMBParm(outp, 4, 0); /* resvd */
3142 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
3143 /* fill in #6 when we have all the parameters' space reserved */
3144 smb_SetSMBParm(outp, 7, 0); /* resv'd */
3145 smb_SetSMBParm(outp, 8, 0); /* resv'd */
3146 smb_SetSMBParm(outp, 9, 0); /* resv'd */
3147 smb_SetSMBParm(outp, 10, 0); /* resv'd */
3148 smb_SetSMBParm(outp, 11, 0); /* reserved */
3150 /* get op ptr after putting in the parms, since otherwise we don't
3151 * know where the data really is.
3153 op = smb_GetSMBData(outp, NULL);
3155 /* now fill in offset from start of SMB header to first data byte (to op) */
3156 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
3158 /* set the packet data length the count of the # of bytes */
3159 smb_SetSMBDataLength(outp, count);
3162 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
3164 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
3167 /* fix some things up */
3168 smb_SetSMBParm(outp, 5, finalCount);
3169 smb_SetSMBDataLength(outp, finalCount);
3171 smb_ReleaseFID(fidp);
3173 cm_ReleaseUser(userp);
3178 * Values for createDisp, copied from NTDDK.H
3180 * FILE_SUPERSEDE 0 (???)
3181 * FILE_OPEN 1 (open)
3182 * FILE_CREATE 2 (exclusive)
3183 * FILE_OPEN_IF 3 (non-exclusive)
3184 * FILE_OVERWRITE 4 (open & truncate, but do not create)
3185 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
3188 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3190 char *pathp, *realPathp;
3194 cm_scache_t *dscp; /* parent dir */
3195 cm_scache_t *scp; /* file to create or open */
3199 unsigned short nameLength;
3201 unsigned int requestOpLock;
3202 unsigned int requestBatchOpLock;
3203 unsigned int mustBeDir;
3204 unsigned int treeCreate;
3206 unsigned int desiredAccess;
3207 unsigned int extAttributes;
3208 unsigned int createDisp;
3209 unsigned int createOptions;
3210 int initialModeBits;
3211 unsigned short baseFid;
3212 smb_fid_t *baseFidp;
3214 cm_scache_t *baseDirp;
3215 unsigned short openAction;
3230 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3231 flags = smb_GetSMBOffsetParm(inp, 3, 1)
3232 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3233 requestOpLock = flags & 0x02;
3234 requestBatchOpLock = flags & 0x04;
3235 mustBeDir = flags & 0x08;
3238 * Why all of a sudden 32-bit FID?
3239 * We will reject all bits higher than 16.
3241 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3242 return CM_ERROR_INVAL;
3243 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3244 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3245 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3246 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3247 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3248 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3249 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3250 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3251 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3253 /* mustBeDir is never set; createOptions directory bit seems to be
3256 if (createOptions & 1)
3258 else if (createOptions & 0x40)
3264 * compute initial mode bits based on read-only flag in
3265 * extended attributes
3267 initialModeBits = 0666;
3268 if (extAttributes & 1) initialModeBits &= ~0222;
3270 pathp = smb_GetSMBData(inp, NULL);
3271 /* Sometimes path is not null-terminated, so we make a copy. */
3272 realPathp = malloc(nameLength+1);
3273 memcpy(realPathp, pathp, nameLength);
3274 realPathp[nameLength] = 0;
3276 spacep = inp->spacep;
3277 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3279 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
3280 osi_Log4(smb_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
3282 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3283 /* special case magic file name for receiving IOCTL requests
3284 * (since IOCTL calls themselves aren't getting through).
3286 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3287 smb_SetupIoctlFid(fidp, spacep);
3289 /* set inp->fid so that later read calls in same msg can find fid */
3290 inp->fid = fidp->fid;
3294 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3295 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3296 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3298 memset(&ft, 0, sizeof(ft));
3299 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3300 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3301 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3302 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3303 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3304 sz.HighPart = 0x7fff; sz.LowPart = 0;
3305 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3306 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3307 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3308 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3309 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
3310 smb_SetSMBDataLength(outp, 0);
3312 /* clean up fid reference */
3313 smb_ReleaseFID(fidp);
3318 #ifdef DEBUG_VERBOSE
3320 char *hexp, *asciip;
3321 asciip = (lastNamep? lastNamep : realPathp);
3322 hexp = osi_HexifyString( asciip );
3323 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
3327 userp = smb_GetUser(vcp, inp);
3329 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
3331 return CM_ERROR_INVAL;
3335 baseDirp = cm_rootSCachep;
3336 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3339 baseFidp = smb_FindFID(vcp, baseFid, 0);
3341 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
3343 cm_ReleaseUser(userp);
3344 return CM_ERROR_INVAL;
3346 baseDirp = baseFidp->scp;
3350 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
3352 /* compute open mode */
3354 if (desiredAccess & DELETE)
3355 fidflags |= SMB_FID_OPENDELETE;
3356 if (desiredAccess & AFS_ACCESS_READ)
3357 fidflags |= SMB_FID_OPENREAD;
3358 if (desiredAccess & AFS_ACCESS_WRITE)
3359 fidflags |= SMB_FID_OPENWRITE;
3363 /* For an exclusive create, we want to do a case sensitive match for the last component. */
3364 if (createDisp == 2 || createDisp == 4 || createDisp == 5) {
3365 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3366 userp, tidPathp, &req, &dscp);
3368 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
3370 if (code == CM_ERROR_NOSUCHFILE) {
3371 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
3372 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
3373 if (code == 0 && realDirFlag == 1) {
3374 cm_ReleaseSCache(scp);
3375 cm_ReleaseSCache(dscp);
3376 cm_ReleaseUser(userp);
3378 return CM_ERROR_EXISTS;
3384 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3385 userp, tidPathp, &req, &scp);
3390 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3391 /* look up parent directory */
3392 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
3393 * the immediate parent. We have to work our way up realPathp until we hit something that we
3401 code = cm_NameI(baseDirp, spacep->data,
3402 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3403 userp, tidPathp, &req, &dscp);
3406 (tp = strrchr(spacep->data,'\\')) &&
3407 (createDisp == 2) &&
3408 (realDirFlag == 1)) {
3411 treeStartp = realPathp + (tp - spacep->data);
3413 if (*tp && !smb_IsLegalFilename(tp)) {
3415 smb_ReleaseFID(baseFidp);
3416 cm_ReleaseUser(userp);
3418 return CM_ERROR_BADNTFILENAME;
3428 smb_ReleaseFID(baseFidp);
3431 osi_Log0(smb_logp,"NTCreateX parent not found");
3432 cm_ReleaseUser(userp);
3437 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
3438 /* A file exists where we want a directory. */
3439 cm_ReleaseSCache(dscp);
3440 cm_ReleaseUser(userp);
3442 return CM_ERROR_EXISTS;
3446 lastNamep = realPathp;
3450 if (!smb_IsLegalFilename(lastNamep)) {
3451 cm_ReleaseSCache(dscp);
3452 cm_ReleaseUser(userp);
3454 return CM_ERROR_BADNTFILENAME;
3457 if (!foundscp && !treeCreate) {
3458 if(createDisp == 2 || createDisp == 4)
3459 code = cm_Lookup(dscp, lastNamep,
3460 CM_FLAG_FOLLOW, userp, &req, &scp);
3462 code = cm_Lookup(dscp, lastNamep,
3463 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3465 if (code && code != CM_ERROR_NOSUCHFILE) {
3466 cm_ReleaseSCache(dscp);
3467 cm_ReleaseUser(userp);
3475 smb_ReleaseFID(baseFidp);
3478 /* if we get here, if code is 0, the file exists and is represented by
3479 * scp. Otherwise, we have to create it. The dir may be represented
3480 * by dscp, or we may have found the file directly. If code is non-zero,
3483 if (code == 0 && !treeCreate) {
3484 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3487 if (dscp) cm_ReleaseSCache(dscp);
3488 cm_ReleaseSCache(scp);
3489 cm_ReleaseUser(userp);
3494 if (createDisp == 2) {
3495 /* oops, file shouldn't be there */
3496 if (dscp) cm_ReleaseSCache(dscp);
3497 cm_ReleaseSCache(scp);
3498 cm_ReleaseUser(userp);
3500 return CM_ERROR_EXISTS;
3504 || createDisp == 5) {
3505 setAttr.mask = CM_ATTRMASK_LENGTH;
3506 setAttr.length.LowPart = 0;
3507 setAttr.length.HighPart = 0;
3508 code = cm_SetAttr(scp, &setAttr, userp, &req);
3509 openAction = 3; /* truncated existing file */
3511 else openAction = 1; /* found existing file */
3513 else if (createDisp == 1 || createDisp == 4) {
3514 /* don't create if not found */
3515 if (dscp) cm_ReleaseSCache(dscp);
3516 cm_ReleaseUser(userp);
3518 return CM_ERROR_NOSUCHFILE;
3520 else if (realDirFlag == 0 || realDirFlag == -1) {
3521 osi_assert(dscp != NULL);
3522 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
3523 osi_LogSaveString(smb_logp, lastNamep));
3524 openAction = 2; /* created file */
3525 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3526 setAttr.clientModTime = time(NULL);
3527 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3529 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3530 smb_NotifyChange(FILE_ACTION_ADDED,
3531 FILE_NOTIFY_CHANGE_FILE_NAME,
3532 dscp, lastNamep, NULL, TRUE);
3533 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3534 /* Not an exclusive create, and someone else tried
3535 * creating it already, then we open it anyway. We
3536 * don't bother retrying after this, since if this next
3537 * fails, that means that the file was deleted after we
3538 * started this call.
3540 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3543 if (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,
3550 } /* lookup succeeded */
3555 char *cp; /* This component */
3556 int clen = 0; /* length of component */
3560 /* create directory */
3561 if ( !treeCreate ) treeStartp = lastNamep;
3562 osi_assert(dscp != NULL);
3563 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
3564 osi_LogSaveString(smb_logp, treeStartp));
3565 openAction = 2; /* created directory */
3567 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3568 setAttr.clientModTime = time(NULL);
3575 tp = strchr(pp, '\\');
3579 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
3583 strncpy(cp,pp,clen);
3589 if(clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
3591 /* cp is the next component to be created. */
3592 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
3593 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
3594 smb_NotifyChange(FILE_ACTION_ADDED,
3595 FILE_NOTIFY_CHANGE_DIR_NAME,
3596 tscp, cp, NULL, TRUE);
3598 (code == CM_ERROR_EXISTS && createDisp != 2)) {
3599 /* Not an exclusive create, and someone else tried
3600 * creating it already, then we open it anyway. We
3601 * don't bother retrying after this, since if this next
3602 * fails, that means that the file was deleted after we
3603 * started this call.
3605 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
3610 if(!isLast) { /* for anything other than dscp, release it unless it's the last one */
3611 cm_ReleaseSCache(tscp);
3612 tscp = scp; /* Newly created directory will be next parent */
3617 if we get here and code == 0, then scp is the last directory created, and tscp is the
3618 parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
3624 /* something went wrong creating or truncating the file */
3625 if (scp) cm_ReleaseSCache(scp);
3626 if (dscp) cm_ReleaseSCache(dscp);
3627 cm_ReleaseUser(userp);
3632 /* make sure we have file vs. dir right (only applies for single component case) */
3633 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3634 cm_ReleaseSCache(scp);
3635 if (dscp) cm_ReleaseSCache(dscp);
3636 cm_ReleaseUser(userp);
3638 return CM_ERROR_ISDIR;
3640 /* (only applies to single component case) */
3641 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3642 cm_ReleaseSCache(scp);
3643 if (dscp) cm_ReleaseSCache(dscp);
3644 cm_ReleaseUser(userp);
3646 return CM_ERROR_NOTDIR;
3649 /* open the file itself */
3650 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3652 /* save a pointer to the vnode */
3655 fidp->flags = fidflags;
3657 /* save parent dir and pathname for delete or change notification */
3658 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3659 fidp->flags |= SMB_FID_NTOPEN;
3660 fidp->NTopen_dscp = dscp;
3661 cm_HoldSCache(dscp);
3662 fidp->NTopen_pathp = strdup(lastNamep);
3664 fidp->NTopen_wholepathp = realPathp;
3666 /* we don't need this any longer */
3667 if (dscp) cm_ReleaseSCache(dscp);
3668 cm_Open(scp, 0, userp);
3670 /* set inp->fid so that later read calls in same msg can find fid */
3671 inp->fid = fidp->fid;
3675 lock_ObtainMutex(&scp->mx);
3676 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3677 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3678 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3679 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3680 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3681 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3682 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3683 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3684 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3686 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3687 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3688 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3689 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3690 smb_SetSMBParmByte(outp, parmSlot,
3691 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3692 lock_ReleaseMutex(&scp->mx);
3693 smb_SetSMBDataLength(outp, 0);
3695 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3696 osi_LogSaveString(smb_logp, realPathp));
3698 smb_ReleaseFID(fidp);
3700 cm_ReleaseUser(userp);
3702 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
3704 /* leave scp held since we put it in fidp->scp */
3709 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3710 * Instead, ultimately, would like to use a subroutine for common code.
3712 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3714 char *pathp, *realPathp;
3718 cm_scache_t *dscp; /* parent dir */
3719 cm_scache_t *scp; /* file to create or open */
3722 unsigned long nameLength;
3724 unsigned int requestOpLock;
3725 unsigned int requestBatchOpLock;
3726 unsigned int mustBeDir;
3727 unsigned int extendedRespRequired;
3729 unsigned int desiredAccess;
3730 #ifdef DEBUG_VERBOSE
3731 unsigned int allocSize;
3732 unsigned int shareAccess;
3734 unsigned int extAttributes;
3735 unsigned int createDisp;
3736 #ifdef DEBUG_VERBOSE
3739 unsigned int createOptions;
3740 int initialModeBits;
3741 unsigned short baseFid;
3742 smb_fid_t *baseFidp;
3744 cm_scache_t *baseDirp;
3745 unsigned short openAction;
3751 int parmOffset, dataOffset;
3762 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3763 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3764 parmp = inp->data + parmOffset;
3765 lparmp = (ULONG *) parmp;
3768 requestOpLock = flags & 0x02;
3769 requestBatchOpLock = flags & 0x04;
3770 mustBeDir = flags & 0x08;
3771 extendedRespRequired = flags & 0x10;
3774 * Why all of a sudden 32-bit FID?
3775 * We will reject all bits higher than 16.
3777 if (lparmp[1] & 0xFFFF0000)
3778 return CM_ERROR_INVAL;
3779 baseFid = (unsigned short)lparmp[1];
3780 desiredAccess = lparmp[2];
3781 #ifdef DEBUG_VERBOSE
3782 allocSize = lparmp[3];
3783 #endif /* DEBUG_VERSOSE */
3784 extAttributes = lparmp[5];
3786 shareAccess = lparmp[6];
3788 createDisp = lparmp[7];
3789 createOptions = lparmp[8];
3790 #ifdef DEBUG_VERBOSE
3793 nameLength = lparmp[11];
3795 #ifdef DEBUG_VERBOSE
3796 osi_Log4(smb_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
3797 osi_Log2(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
3798 osi_Log1(smb_logp,"... flags[%x]",flags);
3801 /* mustBeDir is never set; createOptions directory bit seems to be
3804 if (createOptions & 1)
3806 else if (createOptions & 0x40)
3812 * compute initial mode bits based on read-only flag in
3813 * extended attributes
3815 initialModeBits = 0666;
3816 if (extAttributes & 1) initialModeBits &= ~0222;
3818 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3819 /* Sometimes path is not null-terminated, so we make a copy. */
3820 realPathp = malloc(nameLength+1);
3821 memcpy(realPathp, pathp, nameLength);
3822 realPathp[nameLength] = 0;
3824 spacep = cm_GetSpace();
3825 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3828 * Nothing here to handle SMB_IOCTL_FILENAME.
3829 * Will add it if necessary.
3832 #ifdef DEBUG_VERBOSE
3834 char *hexp, *asciip;
3835 asciip = (lastNamep? lastNamep : realPathp);
3836 hexp = osi_HexifyString( asciip );
3837 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
3842 userp = smb_GetUser(vcp, inp);
3844 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
3846 return CM_ERROR_INVAL;
3850 baseDirp = cm_rootSCachep;
3851 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3854 baseFidp = smb_FindFID(vcp, baseFid, 0);
3856 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
3858 cm_ReleaseUser(userp);
3859 return CM_ERROR_INVAL;
3861 baseDirp = baseFidp->scp;
3865 /* compute open mode */
3867 if (desiredAccess & DELETE)
3868 fidflags |= SMB_FID_OPENDELETE;
3869 if (desiredAccess & AFS_ACCESS_READ)
3870 fidflags |= SMB_FID_OPENREAD;
3871 if (desiredAccess & AFS_ACCESS_WRITE)
3872 fidflags |= SMB_FID_OPENWRITE;
3876 if (createDisp == 2 || createDisp == 4 || createDisp == 5) {
3877 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3878 userp, tidPathp, &req, &dscp);