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(afsd_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(afsd_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(afsd_logp, "SMB3 session setup name %s creating ID %d%s",
191 osi_LogSaveString(afsd_logp, usern), newUid, osi_LogSaveString(afsd_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(afsd_logp, "SMB3 user logoffX uid %d name %s%s%s",
217 osi_LogSaveString(afsd_logp,
218 (uidp->unp) ? uidp->unp->name: " "), s1, s2);
220 lock_ObtainMutex(&uidp->mx);
221 uidp->flags |= SMB_USERFLAG_DELETE;
223 * it doesn't get deleted right away
224 * because the vcp points to it
226 lock_ReleaseMutex(&uidp->mx);
229 osi_Log0(afsd_logp, "SMB3 user logoffX");
231 smb_SetSMBDataLength(outp, 0);
235 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
238 unsigned short newTid;
248 osi_Log0(afsd_logp, "SMB3 receive tree connect");
250 /* parse input parameters */
251 tp = smb_GetSMBData(inp, NULL);
252 passwordp = smb_ParseString(tp, &tp);
253 pathp = smb_ParseString(tp, &tp);
254 servicep = smb_ParseString(tp, &tp);
256 tp = strrchr(pathp, '\\');
258 return CM_ERROR_BADSMB;
260 strcpy(shareName, tp+1);
262 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0)
263 return CM_ERROR_NOIPC;
265 userp = smb_GetUser(vcp, inp);
267 lock_ObtainMutex(&vcp->mx);
268 newTid = vcp->tidCounter++;
269 lock_ReleaseMutex(&vcp->mx);
271 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
272 shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
274 smb_ReleaseTID(tidp);
275 return CM_ERROR_BADSHARENAME;
277 lock_ObtainMutex(&tidp->mx);
279 tidp->pathname = sharePath;
280 lock_ReleaseMutex(&tidp->mx);
281 smb_ReleaseTID(tidp);
283 if (vcp->flags & SMB_VCFLAG_USENT)
284 smb_SetSMBParm(outp, 2, 0); /* OptionalSupport bits */
286 ((smb_t *)outp)->tid = newTid;
287 ((smb_t *)inp)->tid = newTid;
288 tp = smb_GetSMBData(outp, NULL);
292 smb_SetSMBDataLength(outp, 3);
294 osi_Log1(afsd_logp, "SMB3 tree connect created ID %d", newTid);
298 /* must be called with global tran lock held */
299 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
301 smb_tran2Packet_t *tp;
304 smbp = (smb_t *) inp->data;
305 for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
306 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
312 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
313 int totalParms, int totalData)
315 smb_tran2Packet_t *tp;
318 smbp = (smb_t *) inp->data;
319 tp = malloc(sizeof(*tp));
320 memset(tp, 0, sizeof(*tp));
323 tp->curData = tp->curParms = 0;
324 tp->totalData = totalData;
325 tp->totalParms = totalParms;
330 tp->res[0] = smbp->res[0];
331 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
332 tp->opcode = smb_GetSMBParm(inp, 14);
334 tp->parmsp = malloc(totalParms);
336 tp->datap = malloc(totalData);
337 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
341 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
342 smb_tran2Packet_t *inp, smb_packet_t *outp,
343 int totalParms, int totalData)
345 smb_tran2Packet_t *tp;
346 unsigned short parmOffset;
347 unsigned short dataOffset;
348 unsigned short dataAlign;
350 tp = malloc(sizeof(*tp));
351 memset(tp, 0, sizeof(*tp));
353 tp->curData = tp->curParms = 0;
354 tp->totalData = totalData;
355 tp->totalParms = totalParms;
356 tp->oldTotalParms = totalParms;
361 tp->res[0] = inp->res[0];
362 tp->opcode = inp->opcode;
365 * We calculate where the parameters and data will start.
366 * This calculation must parallel the calculation in
367 * smb_SendTran2Packet.
370 parmOffset = 10*2 + 35;
371 parmOffset++; /* round to even */
372 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
374 dataOffset = parmOffset + totalParms;
375 dataAlign = dataOffset & 2; /* quad-align */
376 dataOffset += dataAlign;
377 tp->datap = outp->data + dataOffset;
382 /* free a tran2 packet; must be called with smb_globalLock held */
383 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
385 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
386 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
395 /* called with a VC, an input packet to respond to, and an error code.
396 * sends an error response.
398 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
399 smb_packet_t *tp, long code)
402 unsigned short errCode;
403 unsigned char errClass;
404 unsigned long NTStatus;
406 if (vcp->flags & SMB_VCFLAG_STATUS32)
407 smb_MapNTError(code, &NTStatus);
409 smb_MapCoreError(code, vcp, &errCode, &errClass);
411 smb_FormatResponsePacket(vcp, NULL, tp);
414 /* We can handle long names */
415 if (vcp->flags & SMB_VCFLAG_USENT)
416 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
418 /* now copy important fields from the tran 2 packet */
419 smbp->com = 0x32; /* tran 2 response */
420 smbp->tid = t2p->tid;
421 smbp->mid = t2p->mid;
422 smbp->pid = t2p->pid;
423 smbp->uid = t2p->uid;
424 smbp->res[0] = t2p->res[0];
425 if (vcp->flags & SMB_VCFLAG_STATUS32) {
426 smbp->rcls = (unsigned char) (NTStatus & 0xff);
427 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
428 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
429 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
430 smbp->flg2 |= 0x4000;
433 smbp->rcls = errClass;
434 smbp->errLow = (unsigned char) (errCode & 0xff);
435 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
439 smb_SendPacket(vcp, tp);
442 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
445 unsigned short parmOffset;
446 unsigned short dataOffset;
447 unsigned short totalLength;
448 unsigned short dataAlign;
451 smb_FormatResponsePacket(vcp, NULL, tp);
454 /* We can handle long names */
455 if (vcp->flags & SMB_VCFLAG_USENT)
456 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
458 /* now copy important fields from the tran 2 packet */
459 smbp->com = 0x32; /* tran 2 response */
460 smbp->tid = t2p->tid;
461 smbp->mid = t2p->mid;
462 smbp->pid = t2p->pid;
463 smbp->uid = t2p->uid;
464 smbp->res[0] = t2p->res[0];
466 totalLength = 1 + t2p->totalData + t2p->totalParms;
468 /* now add the core parameters (tran2 info) to the packet */
469 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
470 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
471 smb_SetSMBParm(tp, 2, 0); /* reserved */
472 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
473 parmOffset = 10*2 + 35; /* parm offset in packet */
474 parmOffset++; /* round to even */
475 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
476 * hdr, bcc and wct */
477 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
478 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
479 dataOffset = parmOffset + t2p->oldTotalParms;
480 dataAlign = dataOffset & 2; /* quad-align */
481 dataOffset += dataAlign;
482 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
483 smb_SetSMBParm(tp, 8, 0); /* data displacement */
484 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
487 datap = smb_GetSMBData(tp, NULL);
488 *datap++ = 0; /* we rounded to even */
490 totalLength += dataAlign;
491 smb_SetSMBDataLength(tp, totalLength);
493 /* next, send the datagram */
494 smb_SendPacket(vcp, tp);
497 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
499 smb_tran2Packet_t *asp;
511 /* We sometimes see 0 word count. What to do? */
512 if (*inp->wctp == 0) {
517 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0");
519 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
520 ptbuf[0] = "Transaction2 word count = 0";
521 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
522 1, inp->ncb_length, ptbuf, inp);
523 DeregisterEventSource(h);
525 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0");
528 smb_SetSMBDataLength(outp, 0);
529 smb_SendPacket(vcp, outp);
533 totalParms = smb_GetSMBParm(inp, 0);
534 totalData = smb_GetSMBParm(inp, 1);
536 firstPacket = (inp->inCom == 0x32);
538 /* find the packet we're reassembling */
539 lock_ObtainWrite(&smb_globalLock);
540 asp = smb_FindTran2Packet(vcp, inp);
542 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
544 lock_ReleaseWrite(&smb_globalLock);
546 /* now merge in this latest packet; start by looking up offsets */
548 parmDisp = dataDisp = 0;
549 parmOffset = smb_GetSMBParm(inp, 10);
550 dataOffset = smb_GetSMBParm(inp, 12);
551 parmCount = smb_GetSMBParm(inp, 9);
552 dataCount = smb_GetSMBParm(inp, 11);
553 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
554 asp->maxReturnData = smb_GetSMBParm(inp, 3);
556 osi_Log3(afsd_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
557 totalData, dataCount, asp->maxReturnData);
560 parmDisp = smb_GetSMBParm(inp, 4);
561 parmOffset = smb_GetSMBParm(inp, 3);
562 dataDisp = smb_GetSMBParm(inp, 7);
563 dataOffset = smb_GetSMBParm(inp, 6);
564 parmCount = smb_GetSMBParm(inp, 2);
565 dataCount = smb_GetSMBParm(inp, 5);
567 osi_Log2(afsd_logp, "SMB3 received T2 aux packet parms %d, data %d",
568 parmCount, dataCount);
571 /* now copy the parms and data */
572 if ( parmCount != 0 )
574 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
576 if ( dataCount != 0 ) {
577 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
580 /* account for new bytes */
581 asp->curData += dataCount;
582 asp->curParms += parmCount;
584 /* finally, if we're done, remove the packet from the queue and dispatch it */
585 if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
586 /* we've received it all */
587 lock_ObtainWrite(&smb_globalLock);
588 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
589 lock_ReleaseWrite(&smb_globalLock);
591 /* now dispatch it */
592 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
593 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
594 osi_Log4(afsd_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
595 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
598 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
599 osi_Log4(afsd_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
600 code = CM_ERROR_BADOP;
603 /* if an error is returned, we're supposed to send an error packet,
604 * otherwise the dispatched function already did the data sending.
605 * We give dispatched proc the responsibility since it knows how much
609 smb_SendTran2Error(vcp, asp, outp, code);
612 /* free the input tran 2 packet */
613 lock_ObtainWrite(&smb_globalLock);
614 smb_FreeTran2Packet(asp);
615 lock_ReleaseWrite(&smb_globalLock);
617 else if (firstPacket) {
618 /* the first packet in a multi-packet request, we need to send an
619 * ack to get more data.
621 smb_SetSMBDataLength(outp, 0);
622 smb_SendPacket(vcp, outp);
628 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
631 smb_tran2Packet_t *outp;
636 cm_scache_t *dscp; /* dir we're dealing with */
637 cm_scache_t *scp; /* file we're creating */
649 int parmSlot; /* which parm we're dealing with */
658 extraInfo = (p->parmsp[0] & 1); /* return extra info */
659 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
661 openFun = p->parmsp[6]; /* open function */
662 excl = ((openFun & 3) == 0);
663 trunc = ((openFun & 3) == 2); /* truncate it */
664 openMode = (p->parmsp[1] & 0x7);
665 openAction = 0; /* tracks what we did */
667 attributes = p->parmsp[3];
668 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
670 /* compute initial mode bits based on read-only flag in attributes */
671 initialModeBits = 0666;
672 if (attributes & 1) initialModeBits &= ~0222;
674 pathp = (char *) (&p->parmsp[14]);
676 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
678 spacep = cm_GetSpace();
679 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
681 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
682 /* special case magic file name for receiving IOCTL requests
683 * (since IOCTL calls themselves aren't getting through).
685 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
686 smb_SetupIoctlFid(fidp, spacep);
688 /* copy out remainder of the parms */
690 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
692 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
693 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
694 outp->parmsp[parmSlot] = 0; parmSlot++;
695 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
696 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
697 outp->parmsp[parmSlot] = openMode; parmSlot++;
698 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
699 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
701 /* and the final "always present" stuff */
702 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
703 /* next write out the "unique" ID */
704 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
705 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
706 outp->parmsp[parmSlot] = 0; parmSlot++;
707 if (returnEALength) {
708 outp->parmsp[parmSlot] = 0; parmSlot++;
709 outp->parmsp[parmSlot] = 0; parmSlot++;
713 outp->totalParms = parmSlot * 2;
715 smb_SendTran2Packet(vcp, outp, op);
717 smb_FreeTran2Packet(outp);
719 /* and clean up fid reference */
720 smb_ReleaseFID(fidp);
727 asciip = (lastNamep ? lastNamep : pathp);
728 hexp = osi_HexifyString( asciip );
729 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
734 userp = smb_GetTran2User(vcp, p);
735 /* In the off chance that userp is NULL, we log and abandon */
737 osi_Log1(afsd_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
738 smb_FreeTran2Packet(outp);
739 return CM_ERROR_BADSMB;
742 tidPathp = smb_GetTIDPath(vcp, p->tid);
745 code = cm_NameI(cm_rootSCachep, pathp,
746 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
747 userp, tidPathp, &req, &scp);
749 code = cm_NameI(cm_rootSCachep, spacep->data,
750 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
751 userp, tidPathp, &req, &dscp);
752 cm_FreeSpace(spacep);
755 cm_ReleaseUser(userp);
756 smb_FreeTran2Packet(outp);
760 /* otherwise, scp points to the parent directory. Do a lookup,
761 * and truncate the file if we find it, otherwise we create the
764 if (!lastNamep) lastNamep = pathp;
766 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
768 if (code && code != CM_ERROR_NOSUCHFILE) {
769 cm_ReleaseSCache(dscp);
770 cm_ReleaseUser(userp);
771 smb_FreeTran2Packet(outp);
776 cm_FreeSpace(spacep);
779 /* if we get here, if code is 0, the file exists and is represented by
780 * scp. Otherwise, we have to create it.
783 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
785 if (dscp) cm_ReleaseSCache(dscp);
786 cm_ReleaseSCache(scp);
787 cm_ReleaseUser(userp);
788 smb_FreeTran2Packet(outp);
793 /* oops, file shouldn't be there */
794 if (dscp) cm_ReleaseSCache(dscp);
795 cm_ReleaseSCache(scp);
796 cm_ReleaseUser(userp);
797 smb_FreeTran2Packet(outp);
798 return CM_ERROR_EXISTS;
802 setAttr.mask = CM_ATTRMASK_LENGTH;
803 setAttr.length.LowPart = 0;
804 setAttr.length.HighPart = 0;
805 code = cm_SetAttr(scp, &setAttr, userp, &req);
806 openAction = 3; /* truncated existing file */
808 else openAction = 1; /* found existing file */
810 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
811 /* don't create if not found */
812 if (dscp) cm_ReleaseSCache(dscp);
813 osi_assert(scp == NULL);
814 cm_ReleaseUser(userp);
815 smb_FreeTran2Packet(outp);
816 return CM_ERROR_NOSUCHFILE;
819 osi_assert(dscp != NULL && scp == NULL);
820 openAction = 2; /* created file */
821 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
822 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
823 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
825 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
826 smb_NotifyChange(FILE_ACTION_ADDED,
827 FILE_NOTIFY_CHANGE_FILE_NAME,
828 dscp, lastNamep, NULL, TRUE);
829 if (!excl && code == CM_ERROR_EXISTS) {
830 /* not an exclusive create, and someone else tried
831 * creating it already, then we open it anyway. We
832 * don't bother retrying after this, since if this next
833 * fails, that means that the file was deleted after we
836 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
840 setAttr.mask = CM_ATTRMASK_LENGTH;
841 setAttr.length.LowPart = 0;
842 setAttr.length.HighPart = 0;
843 code = cm_SetAttr(scp, &setAttr, userp,
846 } /* lookup succeeded */
850 /* we don't need this any longer */
851 if (dscp) cm_ReleaseSCache(dscp);
854 /* something went wrong creating or truncating the file */
855 if (scp) cm_ReleaseSCache(scp);
856 cm_ReleaseUser(userp);
857 smb_FreeTran2Packet(outp);
861 /* make sure we're about to open a file */
862 if (scp->fileType != CM_SCACHETYPE_FILE) {
863 cm_ReleaseSCache(scp);
864 cm_ReleaseUser(userp);
865 smb_FreeTran2Packet(outp);
866 return CM_ERROR_ISDIR;
869 /* now all we have to do is open the file itself */
870 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
873 /* save a pointer to the vnode */
876 /* compute open mode */
877 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
878 if (openMode == 1 || openMode == 2)
879 fidp->flags |= SMB_FID_OPENWRITE;
881 smb_ReleaseFID(fidp);
883 cm_Open(scp, 0, userp);
885 /* copy out remainder of the parms */
887 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
888 lock_ObtainMutex(&scp->mx);
890 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
891 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
892 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
893 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
894 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
896 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
898 outp->parmsp[parmSlot] = openMode; parmSlot++;
899 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
900 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
902 /* and the final "always present" stuff */
903 outp->parmsp[parmSlot] = openAction; parmSlot++;
904 /* next write out the "unique" ID */
905 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
906 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
907 outp->parmsp[parmSlot] = 0; parmSlot++;
908 if (returnEALength) {
909 outp->parmsp[parmSlot] = 0; parmSlot++;
910 outp->parmsp[parmSlot] = 0; parmSlot++;
912 lock_ReleaseMutex(&scp->mx);
913 outp->totalData = 0; /* total # of data bytes */
914 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
916 smb_SendTran2Packet(vcp, outp, op);
918 smb_FreeTran2Packet(outp);
920 cm_ReleaseUser(userp);
921 /* leave scp held since we put it in fidp->scp */
925 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
927 return CM_ERROR_BADOP;
930 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
932 return CM_ERROR_BADOP;
935 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
937 smb_tran2Packet_t *outp;
938 smb_tran2QFSInfo_t qi;
941 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
943 osi_Log1(afsd_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
945 switch (p->parmsp[0]) {
946 case 1: responseSize = sizeof(qi.u.allocInfo); break;
947 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
948 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
949 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
950 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
951 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
952 default: return CM_ERROR_INVAL;
955 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
956 switch (p->parmsp[0]) {
959 qi.u.allocInfo.FSID = 0;
960 qi.u.allocInfo.sectorsPerAllocUnit = 1;
961 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
962 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
963 qi.u.allocInfo.bytesPerSector = 1024;
968 qi.u.volumeInfo.vsn = 1234;
969 qi.u.volumeInfo.vnCount = 4;
970 /* we're supposed to pad it out with zeroes to the end */
971 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
972 memcpy(qi.u.volumeInfo.label, "AFS", 4);
977 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
978 qi.u.FSvolumeInfo.vsn = 1234;
979 qi.u.FSvolumeInfo.vnCount = 8;
980 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
986 temp.LowPart = 0x7fffffff;
987 qi.u.FSsizeInfo.totalAllocUnits = temp;
988 temp.LowPart = 0x3fffffff;
989 qi.u.FSsizeInfo.availAllocUnits = temp;
990 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
991 qi.u.FSsizeInfo.bytesPerSector = 1024;
996 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
997 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
1001 /* FS attribute info */
1002 /* attributes, defined in WINNT.H:
1003 * FILE_CASE_SENSITIVE_SEARCH 0x1
1004 * FILE_CASE_PRESERVED_NAMES 0x2
1005 * <no name defined> 0x4000
1006 * If bit 0x4000 is not set, Windows 95 thinks
1007 * we can't handle long (non-8.3) names,
1008 * despite our protestations to the contrary.
1010 qi.u.FSattributeInfo.attributes = 0x4003;
1011 qi.u.FSattributeInfo.maxCompLength = 255;
1012 qi.u.FSattributeInfo.FSnameLength = 6;
1013 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
1017 /* copy out return data, and set corresponding sizes */
1018 outp->totalParms = 0;
1019 outp->totalData = responseSize;
1020 memcpy(outp->datap, &qi, responseSize);
1022 /* send and free the packets */
1023 smb_SendTran2Packet(vcp, outp, op);
1024 smb_FreeTran2Packet(outp);
1029 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1031 return CM_ERROR_BADOP;
1034 struct smb_ShortNameRock {
1038 size_t shortNameLen;
1041 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
1044 struct smb_ShortNameRock *rockp;
1048 /* compare both names and vnodes, though probably just comparing vnodes
1049 * would be safe enough.
1051 if (stricmp(dep->name, rockp->maskp) != 0)
1053 if (ntohl(dep->fid.vnode) != rockp->vnode)
1055 /* This is the entry */
1056 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1057 rockp->shortNameLen = shortNameEnd - rockp->shortName;
1058 return CM_ERROR_STOPNOW;
1061 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1062 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1064 struct smb_ShortNameRock rock;
1068 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1072 spacep = cm_GetSpace();
1073 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1075 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1077 cm_FreeSpace(spacep);
1078 if (code) return code;
1080 if (!lastNamep) lastNamep = pathp;
1083 thyper.HighPart = 0;
1084 rock.shortName = shortName;
1086 rock.maskp = lastNamep;
1087 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1090 cm_ReleaseSCache(dscp);
1093 return CM_ERROR_NOSUCHFILE;
1094 if (code == CM_ERROR_STOPNOW) {
1095 *shortNameLenp = rock.shortNameLen;
1101 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1103 smb_tran2Packet_t *outp;
1104 unsigned long dosTime;
1106 unsigned short infoLevel;
1108 unsigned short attributes;
1109 unsigned long extAttributes;
1114 cm_scache_t *scp, *dscp;
1123 infoLevel = p->parmsp[0];
1124 if (infoLevel == 6) nbytesRequired = 0;
1125 else if (infoLevel == 1) nbytesRequired = 22;
1126 else if (infoLevel == 2) nbytesRequired = 26;
1127 else if (infoLevel == 0x101) nbytesRequired = 40;
1128 else if (infoLevel == 0x102) nbytesRequired = 24;
1129 else if (infoLevel == 0x103) nbytesRequired = 4;
1130 else if (infoLevel == 0x108) nbytesRequired = 30;
1132 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1133 p->opcode, infoLevel);
1134 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1137 osi_Log2(afsd_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1138 osi_LogSaveString(afsd_logp, (char *)(&p->parmsp[3])));
1140 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1142 if (infoLevel > 0x100)
1143 outp->totalParms = 2;
1145 outp->totalParms = 0;
1146 outp->totalData = nbytesRequired;
1148 /* now, if we're at infoLevel 6, we're only being asked to check
1149 * the syntax, so we just OK things now. In particular, we're *not*
1150 * being asked to verify anything about the state of any parent dirs.
1152 if (infoLevel == 6) {
1153 smb_SendTran2Packet(vcp, outp, opx);
1154 smb_FreeTran2Packet(outp);
1158 userp = smb_GetTran2User(vcp, p);
1160 osi_Log1(afsd_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
1161 smb_FreeTran2Packet(outp);
1162 return CM_ERROR_BADSMB;
1165 tidPathp = smb_GetTIDPath(vcp, p->tid);
1168 * XXX Strange hack XXX
1170 * As of Patch 7 (13 January 98), we are having the following problem:
1171 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1172 * requests to look up "desktop.ini" in all the subdirectories.
1173 * This can cause zillions of timeouts looking up non-existent cells
1174 * and volumes, especially in the top-level directory.
1176 * We have not found any way to avoid this or work around it except
1177 * to explicitly ignore the requests for mount points that haven't
1178 * yet been evaluated and for directories that haven't yet been
1181 if (infoLevel == 0x101) {
1182 spacep = cm_GetSpace();
1183 smb_StripLastComponent(spacep->data, &lastComp,
1184 (char *)(&p->parmsp[3]));
1185 /* Make sure that lastComp is not NULL */
1187 if (strcmp(lastComp, "\\desktop.ini") == 0) {
1188 code = cm_NameI(cm_rootSCachep, spacep->data,
1192 userp, tidPathp, &req, &dscp);
1194 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1195 && !dscp->mountRootFidp)
1196 code = CM_ERROR_NOSUCHFILE;
1197 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1198 cm_buf_t *bp = buf_Find(dscp, &hzero);
1202 code = CM_ERROR_NOSUCHFILE;
1204 cm_ReleaseSCache(dscp);
1206 cm_FreeSpace(spacep);
1207 cm_ReleaseUser(userp);
1208 smb_SendTran2Error(vcp, p, opx, code);
1209 smb_FreeTran2Packet(outp);
1215 cm_FreeSpace(spacep);
1218 /* now do namei and stat, and copy out the info */
1219 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1220 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1223 cm_ReleaseUser(userp);
1224 smb_SendTran2Error(vcp, p, opx, code);
1225 smb_FreeTran2Packet(outp);
1229 lock_ObtainMutex(&scp->mx);
1230 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1231 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1232 if (code) goto done;
1234 /* now we have the status in the cache entry, and everything is locked.
1235 * Marshall the output data.
1238 /* for info level 108, figure out short name */
1239 if (infoLevel == 0x108) {
1240 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1241 tidPathp, scp->fid.vnode, shortName,
1248 *((u_long *)op) = len * 2; op += 4;
1249 mbstowcs((unsigned short *)op, shortName, len);
1254 if (infoLevel == 1 || infoLevel == 2) {
1255 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1256 *((u_long *)op) = dosTime; op += 4; /* creation time */
1257 *((u_long *)op) = dosTime; op += 4; /* access time */
1258 *((u_long *)op) = dosTime; op += 4; /* write time */
1259 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1260 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1261 attributes = smb_Attributes(scp);
1262 *((u_short *)op) = attributes; op += 2; /* attributes */
1264 else if (infoLevel == 0x101) {
1265 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1266 *((FILETIME *)op) = ft; op += 8; /* creation time */
1267 *((FILETIME *)op) = ft; op += 8; /* last access time */
1268 *((FILETIME *)op) = ft; op += 8; /* last write time */
1269 *((FILETIME *)op) = ft; op += 8; /* last change time */
1270 extAttributes = smb_ExtAttributes(scp);
1271 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1272 *((u_long *)op) = 0; op += 4; /* don't know what this is */
1274 else if (infoLevel == 0x102) {
1275 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1276 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1277 *((u_long *)op) = scp->linkCount; op += 4;
1280 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1283 else if (infoLevel == 0x103) {
1284 memset(op, 0, 4); op += 4; /* EA size */
1287 /* now, if we are being asked about extended attrs, return a 0 size */
1288 if (infoLevel == 2) {
1289 *((u_long *)op) = 0; op += 4;
1293 /* send and free the packets */
1295 lock_ReleaseMutex(&scp->mx);
1296 cm_ReleaseSCache(scp);
1297 cm_ReleaseUser(userp);
1299 smb_SendTran2Packet(vcp, outp, opx);
1301 smb_SendTran2Error(vcp, p, opx, code);
1302 smb_FreeTran2Packet(outp);
1307 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1309 return CM_ERROR_BADOP;
1312 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1314 smb_tran2Packet_t *outp;
1316 unsigned long attributes;
1317 unsigned short infoLevel;
1330 fidp = smb_FindFID(vcp, fid, 0);
1333 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
1337 infoLevel = p->parmsp[1];
1338 if (infoLevel == 0x101) nbytesRequired = 40;
1339 else if (infoLevel == 0x102) nbytesRequired = 24;
1340 else if (infoLevel == 0x103) nbytesRequired = 4;
1341 else if (infoLevel == 0x104) nbytesRequired = 6;
1343 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1344 p->opcode, infoLevel);
1345 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1346 smb_ReleaseFID(fidp);
1349 osi_Log2(afsd_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1351 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1353 if (infoLevel > 0x100)
1354 outp->totalParms = 2;
1356 outp->totalParms = 0;
1357 outp->totalData = nbytesRequired;
1359 userp = smb_GetTran2User(vcp, p);
1361 osi_Log1(afsd_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
1362 code = CM_ERROR_BADSMB;
1367 lock_ObtainMutex(&scp->mx);
1368 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1369 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1370 if (code) goto done;
1372 /* now we have the status in the cache entry, and everything is locked.
1373 * Marshall the output data.
1376 if (infoLevel == 0x101) {
1377 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1378 *((FILETIME *)op) = ft; op += 8; /* creation time */
1379 *((FILETIME *)op) = ft; op += 8; /* last access time */
1380 *((FILETIME *)op) = ft; op += 8; /* last write time */
1381 *((FILETIME *)op) = ft; op += 8; /* last change time */
1382 attributes = smb_ExtAttributes(scp);
1383 *((u_long *)op) = attributes; op += 4;
1384 *((u_long *)op) = 0; op += 4;
1386 else if (infoLevel == 0x102) {
1387 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1388 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1389 *((u_long *)op) = scp->linkCount; op += 4;
1390 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1391 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1395 else if (infoLevel == 0x103) {
1396 *((u_long *)op) = 0; op += 4;
1398 else if (infoLevel == 0x104) {
1402 if (fidp->NTopen_wholepathp)
1403 name = fidp->NTopen_wholepathp;
1405 name = "\\"; /* probably can't happen */
1407 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
1408 *((u_long *)op) = len * 2; op += 4;
1409 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1412 /* send and free the packets */
1414 lock_ReleaseMutex(&scp->mx);
1415 cm_ReleaseUser(userp);
1416 smb_ReleaseFID(fidp);
1417 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1418 else smb_SendTran2Error(vcp, p, opx, code);
1419 smb_FreeTran2Packet(outp);
1424 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1429 unsigned short infoLevel;
1430 smb_tran2Packet_t *outp;
1438 fidp = smb_FindFID(vcp, fid, 0);
1441 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1445 infoLevel = p->parmsp[1];
1446 if (infoLevel > 0x104 || infoLevel < 0x101) {
1447 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1448 p->opcode, infoLevel);
1449 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1450 smb_ReleaseFID(fidp);
1454 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1455 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1456 smb_ReleaseFID(fidp);
1459 if ((infoLevel == 0x103 || infoLevel == 0x104)
1460 && !(fidp->flags & SMB_FID_OPENWRITE)) {
1461 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1462 smb_ReleaseFID(fidp);
1466 osi_Log1(afsd_logp, "T2 SFileInfo type 0x%x", infoLevel);
1468 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1470 outp->totalParms = 2;
1471 outp->totalData = 0;
1473 userp = smb_GetTran2User(vcp, p);
1475 osi_Log1(afsd_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
1476 code = CM_ERROR_BADSMB;
1482 if (infoLevel == 0x101) {
1484 unsigned int attribute;
1487 /* lock the vnode with a callback; we need the current status
1488 * to determine what the new status is, in some cases.
1490 lock_ObtainMutex(&scp->mx);
1491 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1492 CM_SCACHESYNC_GETSTATUS
1493 | CM_SCACHESYNC_NEEDCALLBACK);
1495 lock_ReleaseMutex(&scp->mx);
1499 /* prepare for setattr call */
1502 lastMod = *((FILETIME *)(p->datap + 16));
1503 /* when called as result of move a b, lastMod is (-1, -1).
1504 * If the check for -1 is not present, timestamp
1505 * of the resulting file will be 1969 (-1)
1507 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
1508 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
1509 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1510 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1512 fidp->flags |= SMB_FID_MTIMESETDONE;
1515 attribute = *((u_long *)(p->datap + 32));
1516 if (attribute != 0) {
1517 if ((scp->unixModeBits & 0222)
1518 && (attribute & 1) != 0) {
1519 /* make a writable file read-only */
1520 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1521 attr.unixModeBits = scp->unixModeBits & ~0222;
1523 else if ((scp->unixModeBits & 0222) == 0
1524 && (attribute & 1) == 0) {
1525 /* make a read-only file writable */
1526 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1527 attr.unixModeBits = scp->unixModeBits | 0222;
1530 lock_ReleaseMutex(&scp->mx);
1534 code = cm_SetAttr(scp, &attr, userp, &req);
1538 else if (infoLevel == 0x103 || infoLevel == 0x104) {
1539 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1542 attr.mask = CM_ATTRMASK_LENGTH;
1543 attr.length.LowPart = size.LowPart;
1544 attr.length.HighPart = size.HighPart;
1545 code = cm_SetAttr(scp, &attr, userp, &req);
1547 else if (infoLevel == 0x102) {
1548 if (*((char *)(p->datap))) {
1549 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1552 fidp->flags |= SMB_FID_DELONCLOSE;
1556 fidp->flags &= ~SMB_FID_DELONCLOSE;
1560 cm_ReleaseUser(userp);
1561 smb_ReleaseFID(fidp);
1562 if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1563 else smb_SendTran2Error(vcp, p, op, code);
1564 smb_FreeTran2Packet(outp);
1569 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1571 return CM_ERROR_BADOP;
1574 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1576 return CM_ERROR_BADOP;
1579 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1581 return CM_ERROR_BADOP;
1584 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1586 return CM_ERROR_BADOP;
1589 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1591 return CM_ERROR_BADOP;
1594 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1595 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1600 cm_scache_t *targetScp; /* target if scp is a symlink */
1605 unsigned short attr;
1606 unsigned long lattr;
1607 smb_dirListPatch_t *patchp;
1608 smb_dirListPatch_t *npatchp;
1610 for(patchp = *dirPatchespp; patchp; patchp =
1611 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1612 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1614 lock_ObtainMutex(&scp->mx);
1615 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1616 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1618 lock_ReleaseMutex(&scp->mx);
1619 cm_ReleaseSCache(scp);
1623 /* now watch for a symlink */
1624 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1625 lock_ReleaseMutex(&scp->mx);
1626 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
1628 /* we have a more accurate file to use (the
1629 * target of the symbolic link). Otherwise,
1630 * we'll just use the symlink anyway.
1632 osi_Log2(afsd_logp, "symlink vp %x to vp %x",
1634 cm_ReleaseSCache(scp);
1637 lock_ObtainMutex(&scp->mx);
1640 dptr = patchp->dptr;
1642 if (infoLevel >= 0x101) {
1644 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1646 /* copy to Creation Time */
1647 *((FILETIME *)dptr) = ft;
1650 /* copy to Last Access Time */
1651 *((FILETIME *)dptr) = ft;
1654 /* copy to Last Write Time */
1655 *((FILETIME *)dptr) = ft;
1658 /* copy to Change Time */
1659 *((FILETIME *)dptr) = ft;
1662 /* Use length for both file length and alloc length */
1663 *((LARGE_INTEGER *)dptr) = scp->length;
1665 *((LARGE_INTEGER *)dptr) = scp->length;
1668 /* Copy attributes */
1669 lattr = smb_ExtAttributes(scp);
1670 /* merge in hidden (dot file) attribute */
1671 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1672 lattr |= SMB_ATTR_HIDDEN;
1673 *((u_long *)dptr) = lattr;
1678 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1680 /* and copy out date */
1681 shortTemp = (dosTime>>16) & 0xffff;
1682 *((u_short *)dptr) = shortTemp;
1685 /* copy out creation time */
1686 shortTemp = dosTime & 0xffff;
1687 *((u_short *)dptr) = shortTemp;
1690 /* and copy out date */
1691 shortTemp = (dosTime>>16) & 0xffff;
1692 *((u_short *)dptr) = shortTemp;
1695 /* copy out access time */
1696 shortTemp = dosTime & 0xffff;
1697 *((u_short *)dptr) = shortTemp;
1700 /* and copy out date */
1701 shortTemp = (dosTime>>16) & 0xffff;
1702 *((u_short *)dptr) = shortTemp;
1705 /* copy out mod time */
1706 shortTemp = dosTime & 0xffff;
1707 *((u_short *)dptr) = shortTemp;
1710 /* copy out file length and alloc length,
1711 * using the same for both
1713 *((u_long *)dptr) = scp->length.LowPart;
1715 *((u_long *)dptr) = scp->length.LowPart;
1718 /* finally copy out attributes as short */
1719 attr = smb_Attributes(scp);
1720 /* merge in hidden (dot file) attribute */
1721 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1722 attr |= SMB_ATTR_HIDDEN;
1723 *dptr++ = attr & 0xff;
1724 *dptr++ = (attr >> 8) & 0xff;
1727 lock_ReleaseMutex(&scp->mx);
1728 cm_ReleaseSCache(scp);
1731 /* now free the patches */
1732 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1733 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1737 /* and mark the list as empty */
1738 *dirPatchespp = NULL;
1743 /* do a case-folding search of the star name mask with the name in namep.
1744 * Return 1 if we match, otherwise 0.
1746 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1748 unsigned char tcp1, tcp2; /* Pattern characters */
1749 unsigned char tcn1; /* Name characters */
1750 int sawDot = 0, sawStar = 0, req8dot3 = 0;
1751 char *starNamep, *starMaskp;
1752 static char nullCharp[] = {0};
1754 /* make sure we only match 8.3 names, if requested */
1755 req8dot3 = (flags & CM_FLAG_8DOT3);
1756 if (req8dot3 && !cm_Is8Dot3(namep))
1761 /* Next pattern character */
1764 /* Next name character */
1768 /* 0 - end of pattern */
1774 else if (tcp1 == '.' || tcp1 == '"') {
1784 * first dot in pattern;
1785 * must match dot or end of name
1790 else if (tcn1 == '.') {
1799 else if (tcp1 == '?') {
1800 if (tcn1 == 0 || tcn1 == '.')
1805 else if (tcp1 == '>') {
1806 if (tcn1 != 0 && tcn1 != '.')
1810 else if (tcp1 == '*' || tcp1 == '<') {
1814 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
1815 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
1830 * pattern character after '*' is not null or
1831 * period. If it is '?' or '>', we are not
1832 * going to understand it. If it is '*' or
1833 * '<', we are going to skip over it. None of
1834 * these are likely, I hope.
1836 /* skip over '*' and '<' */
1837 while (tcp2 == '*' || tcp2 == '<')
1840 /* skip over characters that don't match tcp2 */
1841 while (req8dot3 && tcn1 != '.' && tcn1 != 0
1842 && cm_foldUpper[tcn1] != cm_foldUpper[tcp2])
1846 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
1849 /* Remember where we are */
1859 /* tcp1 is not a wildcard */
1860 if (cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) {
1865 /* if trying to match a star pattern, go back */
1867 maskp = starMaskp - 2;
1868 namep = starNamep + 1;
1878 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1887 smb_dirListPatch_t *dirListPatchesp;
1888 smb_dirListPatch_t *curPatchp;
1891 long orbytes; /* # of bytes in this output record */
1892 long ohbytes; /* # of bytes, except file name */
1893 long onbytes; /* # of bytes in name, incl. term. null */
1894 osi_hyper_t dirLength;
1895 osi_hyper_t bufferOffset;
1896 osi_hyper_t curOffset;
1898 smb_dirSearch_t *dsp;
1902 cm_pageHeader_t *pageHeaderp;
1903 cm_user_t *userp = NULL;
1906 long nextEntryCookie;
1907 int numDirChunks; /* # of 32 byte dir chunks in this entry */
1908 char *op; /* output data ptr */
1909 char *origOp; /* original value of op */
1910 cm_space_t *spacep; /* for pathname buffer */
1911 long maxReturnData; /* max # of return data */
1912 long maxReturnParms; /* max # of return parms */
1913 long bytesInBuffer; /* # data bytes in the output buffer */
1915 char *maskp; /* mask part of path */
1919 smb_tran2Packet_t *outp; /* response packet */
1922 char shortName[13]; /* 8.3 name if needed */
1933 if (p->opcode == 1) {
1934 /* find first; obtain basic parameters from request */
1935 attribute = p->parmsp[0];
1936 maxCount = p->parmsp[1];
1937 infoLevel = p->parmsp[3];
1938 searchFlags = p->parmsp[2];
1939 dsp = smb_NewDirSearch(1);
1940 dsp->attribute = attribute;
1941 pathp = ((char *) p->parmsp) + 12; /* points to path */
1943 maskp = strrchr(pathp, '\\');
1944 if (maskp == NULL) maskp = pathp;
1945 else maskp++; /* skip over backslash */
1946 strcpy(dsp->mask, maskp); /* and save mask */
1947 /* track if this is likely to match a lot of entries */
1948 starPattern = smb_V3IsStarMask(maskp);
1951 osi_assert(p->opcode == 2);
1952 /* find next; obtain basic parameters from request or open dir file */
1953 dsp = smb_FindDirSearch(p->parmsp[0]);
1954 if (!dsp) return CM_ERROR_BADFD;
1955 attribute = dsp->attribute;
1956 maxCount = p->parmsp[1];
1957 infoLevel = p->parmsp[2];
1958 searchFlags = p->parmsp[5];
1960 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
1962 starPattern = 1; /* assume, since required a Find Next */
1966 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
1967 attribute, infoLevel, maxCount, searchFlags);
1969 osi_Log2(afsd_logp, "...T2 search op %d, nextCookie 0x%x",
1970 p->opcode, nextCookie);
1972 if (infoLevel >= 0x101)
1973 searchFlags &= ~4; /* no resume keys */
1975 dirListPatchesp = NULL;
1977 maxReturnData = p->maxReturnData;
1978 if (p->opcode == 1) /* find first */
1979 maxReturnParms = 10; /* bytes */
1981 maxReturnParms = 8; /* bytes */
1983 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
1984 if (maxReturnData > 6000)
1985 maxReturnData = 6000;
1986 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
1988 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
1991 osi_Log1(afsd_logp, "T2 receive search dir %s",
1992 osi_LogSaveString(afsd_logp, pathp));
1994 /* bail out if request looks bad */
1995 if (p->opcode == 1 && !pathp) {
1996 smb_ReleaseDirSearch(dsp);
1997 smb_FreeTran2Packet(outp);
1998 return CM_ERROR_BADSMB;
2001 osi_Log2(afsd_logp, "T2 dir search cookie 0x%x, connection %d",
2002 nextCookie, dsp->cookie);
2004 userp = smb_GetTran2User(vcp, p);
2006 osi_Log1(afsd_logp, "T2 dir search unable to resolve user [%d]", p->uid);
2007 smb_ReleaseDirSearch(dsp);
2008 smb_FreeTran2Packet(outp);
2009 return CM_ERROR_BADSMB;
2012 /* try to get the vnode for the path name next */
2013 lock_ObtainMutex(&dsp->mx);
2020 spacep = cm_GetSpace();
2021 smb_StripLastComponent(spacep->data, NULL, pathp);
2022 lock_ReleaseMutex(&dsp->mx);
2024 tidPathp = smb_GetTIDPath(vcp, p->tid);
2025 code = cm_NameI(cm_rootSCachep, spacep->data,
2026 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2027 userp, tidPathp, &req, &scp);
2028 cm_FreeSpace(spacep);
2030 lock_ObtainMutex(&dsp->mx);
2032 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2034 /* we need one hold for the entry we just stored into,
2035 * and one for our own processing. When we're done
2036 * with this function, we'll drop the one for our own
2037 * processing. We held it once from the namei call,
2038 * and so we do another hold now.
2041 lock_ObtainMutex(&scp->mx);
2042 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2043 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2044 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2045 dsp->flags |= SMB_DIRSEARCH_BULKST;
2047 lock_ReleaseMutex(&scp->mx);
2050 lock_ReleaseMutex(&dsp->mx);
2052 cm_ReleaseUser(userp);
2053 smb_FreeTran2Packet(outp);
2054 smb_DeleteDirSearch(dsp);
2055 smb_ReleaseDirSearch(dsp);
2059 /* get the directory size */
2060 lock_ObtainMutex(&scp->mx);
2061 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2062 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2064 lock_ReleaseMutex(&scp->mx);
2065 cm_ReleaseSCache(scp);
2066 cm_ReleaseUser(userp);
2067 smb_FreeTran2Packet(outp);
2068 smb_DeleteDirSearch(dsp);
2069 smb_ReleaseDirSearch(dsp);
2073 dirLength = scp->length;
2075 bufferOffset.LowPart = bufferOffset.HighPart = 0;
2076 curOffset.HighPart = 0;
2077 curOffset.LowPart = nextCookie;
2078 origOp = outp->datap;
2085 if (searchFlags & 4)
2086 /* skip over resume key */
2089 /* make sure that curOffset.LowPart doesn't point to the first
2090 * 32 bytes in the 2nd through last dir page, and that it doesn't
2091 * point at the first 13 32-byte chunks in the first dir page,
2092 * since those are dir and page headers, and don't contain useful
2095 temp = curOffset.LowPart & (2048-1);
2096 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2097 /* we're in the first page */
2098 if (temp < 13*32) temp = 13*32;
2101 /* we're in a later dir page */
2102 if (temp < 32) temp = 32;
2105 /* make sure the low order 5 bits are zero */
2108 /* now put temp bits back ito curOffset.LowPart */
2109 curOffset.LowPart &= ~(2048-1);
2110 curOffset.LowPart |= temp;
2112 /* check if we've passed the dir's EOF */
2113 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2118 /* check if we've returned all the names that will fit in the
2119 * response packet; we check return count as well as the number
2120 * of bytes requested. We check the # of bytes after we find
2121 * the dir entry, since we'll need to check its size.
2123 if (returnedNames >= maxCount) {
2127 /* see if we can use the bufferp we have now; compute in which
2128 * page the current offset would be, and check whether that's
2129 * the offset of the buffer we have. If not, get the buffer.
2131 thyper.HighPart = curOffset.HighPart;
2132 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2133 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2136 buf_Release(bufferp);
2139 lock_ReleaseMutex(&scp->mx);
2140 lock_ObtainRead(&scp->bufCreateLock);
2141 code = buf_Get(scp, &thyper, &bufferp);
2142 lock_ReleaseRead(&scp->bufCreateLock);
2144 /* now, if we're doing a star match, do bulk fetching
2145 * of all of the status info for files in the dir.
2148 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2151 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2152 && LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
2153 /* Don't bulk stat if risking timeout */
2154 int now = GetCurrentTime();
2155 if (now - req.startTime > 5000) {
2156 scp->bulkStatProgress = thyper;
2157 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2158 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2160 cm_TryBulkStat(scp, &thyper, userp, &req);
2164 lock_ObtainMutex(&scp->mx);
2166 bufferOffset = thyper;
2168 /* now get the data in the cache */
2170 code = cm_SyncOp(scp, bufferp, userp, &req,
2172 CM_SCACHESYNC_NEEDCALLBACK
2173 | CM_SCACHESYNC_READ);
2176 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2178 /* otherwise, load the buffer and try again */
2179 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2184 buf_Release(bufferp);
2188 } /* if (wrong buffer) ... */
2190 /* now we have the buffer containing the entry we're interested
2191 * in; copy it out if it represents a non-deleted entry.
2193 entryInDir = curOffset.LowPart & (2048-1);
2194 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2196 /* page header will help tell us which entries are free. Page
2197 * header can change more often than once per buffer, since
2198 * AFS 3 dir page size may be less than (but not more than)
2199 * a buffer package buffer.
2201 /* only look intra-buffer */
2202 temp = curOffset.LowPart & (buf_bufferSize - 1);
2203 temp &= ~(2048 - 1); /* turn off intra-page bits */
2204 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2206 /* now determine which entry we're looking at in the page.
2207 * If it is free (there's a free bitmap at the start of the
2208 * dir), we should skip these 32 bytes.
2210 slotInPage = (entryInDir & 0x7e0) >> 5;
2211 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2212 & (1 << (slotInPage & 0x7)))) {
2213 /* this entry is free */
2214 numDirChunks = 1; /* only skip this guy */
2218 tp = bufferp->datap + entryInBuffer;
2219 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
2221 /* while we're here, compute the next entry's location, too,
2222 * since we'll need it when writing out the cookie into the dir
2225 * XXXX Probably should do more sanity checking.
2227 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2229 /* compute offset of cookie representing next entry */
2230 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
2232 /* Need 8.3 name? */
2234 if (infoLevel == 0x104
2235 && dep->fid.vnode != 0
2236 && !cm_Is8Dot3(dep->name)) {
2237 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2241 if (dep->fid.vnode != 0
2242 && (smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)
2244 && smb_V3MatchMask(shortName, maskp,
2245 CM_FLAG_CASEFOLD)))) {
2247 /* Eliminate entries that don't match requested attributes */
2248 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
2249 smb_IsDotFile(dep->name))
2250 goto nextEntry; /* no hidden files */
2252 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
2254 /* We have already done the cm_TryBulkStat above */
2255 fid.cell = scp->fid.cell;
2256 fid.volume = scp->fid.volume;
2257 fid.vnode = ntohl(dep->fid.vnode);
2258 fid.unique = ntohl(dep->fid.unique);
2259 fileType = cm_FindFileType(&fid);
2260 /*osi_Log2(afsd_logp, "smb_ReceiveTran2SearchDir: file %s "
2261 "has filetype %d", dep->name,
2263 if (fileType == CM_SCACHETYPE_DIRECTORY)
2267 /* finally check if this name will fit */
2269 /* standard dir entry stuff */
2270 if (infoLevel < 0x101)
2271 ohbytes = 23; /* pre-NT */
2272 else if (infoLevel == 0x103)
2273 ohbytes = 12; /* NT names only */
2275 ohbytes = 64; /* NT */
2277 if (infoLevel == 0x104)
2278 ohbytes += 26; /* Short name & length */
2280 if (searchFlags & 4) {
2281 ohbytes += 4; /* if resume key required */
2285 && infoLevel != 0x101
2286 && infoLevel != 0x103)
2287 ohbytes += 4; /* EASIZE */
2289 /* add header to name & term. null */
2290 orbytes = onbytes + ohbytes + 1;
2292 /* now, we round up the record to a 4 byte alignment,
2293 * and we make sure that we have enough room here for
2294 * even the aligned version (so we don't have to worry
2295 * about an * overflow when we pad things out below).
2296 * That's the reason for the alignment arithmetic below.
2298 if (infoLevel >= 0x101)
2299 align = (4 - (orbytes & 3)) & 3;
2302 if (orbytes + bytesInBuffer + align > maxReturnData)
2305 /* this is one of the entries to use: it is not deleted
2306 * and it matches the star pattern we're looking for.
2307 * Put out the name, preceded by its length.
2309 /* First zero everything else */
2310 memset(origOp, 0, ohbytes);
2312 if (infoLevel <= 0x101)
2313 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2314 else if (infoLevel == 0x103)
2315 *((u_long *)(op + 8)) = onbytes;
2317 *((u_long *)(op + 60)) = onbytes;
2318 strcpy(origOp+ohbytes, dep->name);
2320 /* Short name if requested and needed */
2321 if (infoLevel == 0x104) {
2322 if (NeedShortName) {
2323 strcpy(op + 70, shortName);
2324 *(op + 68) = shortNameEnd - shortName;
2328 /* now, adjust the # of entries copied */
2331 /* NextEntryOffset and FileIndex */
2332 if (infoLevel >= 101) {
2333 int entryOffset = orbytes + align;
2334 *((u_long *)op) = entryOffset;
2335 *((u_long *)(op+4)) = nextEntryCookie;
2338 /* now we emit the attribute. This is tricky, since
2339 * we need to really stat the file to find out what
2340 * type of entry we've got. Right now, we're copying
2341 * out data from * a buffer, while holding the scp
2342 * locked, so it isn't really convenient to stat
2343 * something now. We'll put in a place holder
2344 * now, and make a second pass before returning this
2345 * to get the real attributes. So, we just skip the
2346 * data for now, and adjust it later. We allocate a
2347 * patch record to make it easy to find this point
2348 * later. The replay will happen at a time when it is
2349 * safe to unlock the directory.
2351 if (infoLevel != 0x103) {
2352 curPatchp = malloc(sizeof(*curPatchp));
2353 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2355 curPatchp->dptr = op;
2356 if (infoLevel >= 0x101)
2357 curPatchp->dptr += 8;
2359 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
2360 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
2363 curPatchp->flags = 0;
2365 curPatchp->fid.cell = scp->fid.cell;
2366 curPatchp->fid.volume = scp->fid.volume;
2367 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2368 curPatchp->fid.unique = ntohl(dep->fid.unique);
2371 curPatchp->dep = dep;
2374 if (searchFlags & 4)
2375 /* put out resume key */
2376 *((u_long *)origOp) = nextEntryCookie;
2378 /* Adjust byte ptr and count */
2379 origOp += orbytes; /* skip entire record */
2380 bytesInBuffer += orbytes;
2382 /* and pad the record out */
2383 while (--align >= 0) {
2388 } /* if we're including this name */
2391 /* and adjust curOffset to be where the new cookie is */
2392 thyper.HighPart = 0;
2393 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2394 curOffset = LargeIntegerAdd(thyper, curOffset);
2395 } /* while copying data for dir listing */
2397 /* release the mutex */
2398 lock_ReleaseMutex(&scp->mx);
2399 if (bufferp) buf_Release(bufferp);
2401 /* apply and free last set of patches; if not doing a star match, this
2402 * will be empty, but better safe (and freeing everything) than sorry.
2404 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2407 /* now put out the final parameters */
2408 if (returnedNames == 0) eos = 1;
2409 if (p->opcode == 1) {
2411 outp->parmsp[0] = (unsigned short) dsp->cookie;
2412 outp->parmsp[1] = returnedNames;
2413 outp->parmsp[2] = eos;
2414 outp->parmsp[3] = 0; /* nothing wrong with EAS */
2415 outp->parmsp[4] = 0;
2416 /* don't need last name to continue
2417 * search, cookie is enough. Normally,
2418 * this is the offset of the file name
2419 * of the last entry returned.
2421 outp->totalParms = 10; /* in bytes */
2425 outp->parmsp[0] = returnedNames;
2426 outp->parmsp[1] = eos;
2427 outp->parmsp[2] = 0; /* EAS error */
2428 outp->parmsp[3] = 0; /* last name, as above */
2429 outp->totalParms = 8; /* in bytes */
2432 /* return # of bytes in the buffer */
2433 outp->totalData = bytesInBuffer;
2435 osi_Log2(afsd_logp, "T2 search dir done, %d names, code %d",
2436 returnedNames, code);
2438 /* Return error code if unsuccessful on first request */
2439 if (code == 0 && p->opcode == 1 && returnedNames == 0)
2440 code = CM_ERROR_NOSUCHFILE;
2442 /* if we're supposed to close the search after this request, or if
2443 * we're supposed to close the search if we're done, and we're done,
2444 * or if something went wrong, close the search.
2446 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2447 if ((searchFlags & 1) || (returnedNames == 0) ||
2448 ((searchFlags & 2) && eos) || code != 0)
2449 smb_DeleteDirSearch(dsp);
2451 smb_SendTran2Error(vcp, p, opx, code);
2453 smb_SendTran2Packet(vcp, outp, opx);
2455 smb_FreeTran2Packet(outp);
2456 smb_ReleaseDirSearch(dsp);
2457 cm_ReleaseSCache(scp);
2458 cm_ReleaseUser(userp);
2462 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2465 smb_dirSearch_t *dsp;
2467 dirHandle = smb_GetSMBParm(inp, 0);
2469 osi_Log1(afsd_logp, "SMB3 find close handle %d", dirHandle);
2471 dsp = smb_FindDirSearch(dirHandle);
2474 return CM_ERROR_BADFD;
2476 /* otherwise, we have an FD to destroy */
2477 smb_DeleteDirSearch(dsp);
2478 smb_ReleaseDirSearch(dsp);
2480 /* and return results */
2481 smb_SetSMBDataLength(outp, 0);
2486 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2488 smb_SetSMBDataLength(outp, 0);
2492 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2499 cm_scache_t *dscp; /* dir we're dealing with */
2500 cm_scache_t *scp; /* file we're creating */
2502 int initialModeBits;
2512 int parmSlot; /* which parm we're dealing with */
2520 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
2521 openFun = smb_GetSMBParm(inp, 8); /* open function */
2522 excl = ((openFun & 3) == 0);
2523 trunc = ((openFun & 3) == 2); /* truncate it */
2524 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2525 openAction = 0; /* tracks what we did */
2527 attributes = smb_GetSMBParm(inp, 5);
2528 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2530 /* compute initial mode bits based on read-only flag in attributes */
2531 initialModeBits = 0666;
2532 if (attributes & 1) initialModeBits &= ~0222;
2534 pathp = smb_GetSMBData(inp, NULL);
2536 spacep = inp->spacep;
2537 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2539 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2540 /* special case magic file name for receiving IOCTL requests
2541 * (since IOCTL calls themselves aren't getting through).
2544 osi_Log0(afsd_logp, "IOCTL Open");
2547 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2548 smb_SetupIoctlFid(fidp, spacep);
2550 /* set inp->fid so that later read calls in same msg can find fid */
2551 inp->fid = fidp->fid;
2553 /* copy out remainder of the parms */
2555 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2557 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2558 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
2559 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2560 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
2561 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2562 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2563 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2564 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2566 /* and the final "always present" stuff */
2567 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2568 /* next write out the "unique" ID */
2569 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2570 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2571 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2572 smb_SetSMBDataLength(outp, 0);
2574 /* and clean up fid reference */
2575 smb_ReleaseFID(fidp);
2579 #ifdef DEBUG_VERBOSE
2581 char *hexp, *asciip;
2582 asciip = (lastNamep ? lastNamep : pathp );
2583 hexp = osi_HexifyString(asciip);
2584 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
2588 userp = smb_GetUser(vcp, inp);
2591 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2592 code = cm_NameI(cm_rootSCachep, pathp,
2593 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2594 userp, tidPathp, &req, &scp);
2596 code = cm_NameI(cm_rootSCachep, spacep->data,
2597 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2598 userp, tidPathp, &req, &dscp);
2601 cm_ReleaseUser(userp);
2605 /* otherwise, scp points to the parent directory. Do a lookup,
2606 * and truncate the file if we find it, otherwise we create the
2609 if (!lastNamep) lastNamep = pathp;
2611 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2613 if (code && code != CM_ERROR_NOSUCHFILE) {
2614 cm_ReleaseSCache(dscp);
2615 cm_ReleaseUser(userp);
2620 /* if we get here, if code is 0, the file exists and is represented by
2621 * scp. Otherwise, we have to create it. The dir may be represented
2622 * by dscp, or we may have found the file directly. If code is non-zero,
2626 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2628 if (dscp) cm_ReleaseSCache(dscp);
2629 cm_ReleaseSCache(scp);
2630 cm_ReleaseUser(userp);
2635 /* oops, file shouldn't be there */
2636 if (dscp) cm_ReleaseSCache(dscp);
2637 cm_ReleaseSCache(scp);
2638 cm_ReleaseUser(userp);
2639 return CM_ERROR_EXISTS;
2643 setAttr.mask = CM_ATTRMASK_LENGTH;
2644 setAttr.length.LowPart = 0;
2645 setAttr.length.HighPart = 0;
2646 code = cm_SetAttr(scp, &setAttr, userp, &req);
2647 openAction = 3; /* truncated existing file */
2649 else openAction = 1; /* found existing file */
2651 else if (!(openFun & 0x10)) {
2652 /* don't create if not found */
2653 if (dscp) cm_ReleaseSCache(dscp);
2654 cm_ReleaseUser(userp);
2655 return CM_ERROR_NOSUCHFILE;
2658 osi_assert(dscp != NULL);
2659 osi_Log1(afsd_logp, "smb_ReceiveV3OpenX creating file %s",
2660 osi_LogSaveString(afsd_logp, lastNamep));
2661 openAction = 2; /* created file */
2662 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2663 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2664 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2666 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2667 smb_NotifyChange(FILE_ACTION_ADDED,
2668 FILE_NOTIFY_CHANGE_FILE_NAME,
2669 dscp, lastNamep, NULL, TRUE);
2670 if (!excl && code == CM_ERROR_EXISTS) {
2671 /* not an exclusive create, and someone else tried
2672 * creating it already, then we open it anyway. We
2673 * don't bother retrying after this, since if this next
2674 * fails, that means that the file was deleted after we
2675 * started this call.
2677 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2681 setAttr.mask = CM_ATTRMASK_LENGTH;
2682 setAttr.length.LowPart = 0;
2683 setAttr.length.HighPart = 0;
2684 code = cm_SetAttr(scp, &setAttr, userp, &req);
2686 } /* lookup succeeded */
2690 /* we don't need this any longer */
2691 if (dscp) cm_ReleaseSCache(dscp);
2694 /* something went wrong creating or truncating the file */
2695 if (scp) cm_ReleaseSCache(scp);
2696 cm_ReleaseUser(userp);
2700 /* make sure we're about to open a file */
2701 if (scp->fileType != CM_SCACHETYPE_FILE) {
2702 cm_ReleaseSCache(scp);
2703 cm_ReleaseUser(userp);
2704 return CM_ERROR_ISDIR;
2707 /* now all we have to do is open the file itself */
2708 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2711 /* save a pointer to the vnode */
2714 /* compute open mode */
2715 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2716 if (openMode == 1 || openMode == 2)
2717 fidp->flags |= SMB_FID_OPENWRITE;
2719 smb_ReleaseFID(fidp);
2721 cm_Open(scp, 0, userp);
2723 /* set inp->fid so that later read calls in same msg can find fid */
2724 inp->fid = fidp->fid;
2726 /* copy out remainder of the parms */
2728 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2729 lock_ObtainMutex(&scp->mx);
2731 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2732 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2733 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2734 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2735 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2736 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2737 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2738 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2739 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2741 /* and the final "always present" stuff */
2742 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2743 /* next write out the "unique" ID */
2744 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2745 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2746 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2747 lock_ReleaseMutex(&scp->mx);
2748 smb_SetSMBDataLength(outp, 0);
2750 osi_Log1(afsd_logp, "SMB OpenX opening fid %d", fidp->fid);
2752 cm_ReleaseUser(userp);
2753 /* leave scp held since we put it in fidp->scp */
2757 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2764 unsigned char LockType;
2765 unsigned short NumberOfUnlocks, NumberOfLocks;
2766 unsigned long Timeout;
2768 LARGE_INTEGER LOffset, LLength;
2769 smb_waitingLock_t *waitingLock;
2776 fid = smb_GetSMBParm(inp, 2);
2777 fid = smb_ChainFID(fid, inp);
2779 fidp = smb_FindFID(vcp, fid, 0);
2780 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2781 return CM_ERROR_BADFD;
2783 /* set inp->fid so that later read calls in same msg can find fid */
2786 userp = smb_GetUser(vcp, inp);
2790 lock_ObtainMutex(&scp->mx);
2791 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2792 CM_SCACHESYNC_NEEDCALLBACK
2793 | CM_SCACHESYNC_GETSTATUS
2794 | CM_SCACHESYNC_LOCK);
2795 if (code) goto doneSync;
2797 LockType = smb_GetSMBParm(inp, 3) & 0xff;
2798 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2799 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2800 NumberOfLocks = smb_GetSMBParm(inp, 7);
2802 op = smb_GetSMBData(inp, NULL);
2804 for (i=0; i<NumberOfUnlocks; i++) {
2805 if (LockType & 0x10) {
2807 LOffset.HighPart = *((LONG *)(op + 4));
2808 LOffset.LowPart = *((DWORD *)(op + 8));
2809 LLength.HighPart = *((LONG *)(op + 12));
2810 LLength.LowPart = *((DWORD *)(op + 16));
2814 /* Not Large Files */
2815 LOffset.HighPart = 0;
2816 LOffset.LowPart = *((DWORD *)(op + 2));
2817 LLength.HighPart = 0;
2818 LLength.LowPart = *((DWORD *)(op + 6));
2821 if (LargeIntegerNotEqualToZero(LOffset))
2823 /* Do not check length -- length check done in cm_Unlock */
2825 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2826 if (code) goto done;
2829 for (i=0; i<NumberOfLocks; i++) {
2830 if (LockType & 0x10) {
2832 LOffset.HighPart = *((LONG *)(op + 4));
2833 LOffset.LowPart = *((DWORD *)(op + 8));
2834 LLength.HighPart = *((LONG *)(op + 12));
2835 LLength.LowPart = *((DWORD *)(op + 16));
2839 /* Not Large Files */
2840 LOffset.HighPart = 0;
2841 LOffset.LowPart = *((DWORD *)(op + 2));
2842 LLength.HighPart = 0;
2843 LLength.LowPart = *((DWORD *)(op + 6));
2846 if (LargeIntegerNotEqualToZero(LOffset))
2848 if (LargeIntegerLessThan(LOffset, scp->length))
2851 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2852 userp, &req, &lockp);
2853 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2854 /* Put on waiting list */
2855 waitingLock = malloc(sizeof(smb_waitingLock_t));
2856 waitingLock->vcp = vcp;
2857 waitingLock->inp = smb_CopyPacket(inp);
2858 waitingLock->outp = smb_CopyPacket(outp);
2859 waitingLock->timeRemaining = Timeout;
2860 waitingLock->lockp = lockp;
2861 lock_ObtainWrite(&smb_globalLock);
2862 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2864 osi_Wakeup((long) &smb_allWaitingLocks);
2865 lock_ReleaseWrite(&smb_globalLock);
2866 /* don't send reply immediately */
2867 outp->flags |= SMB_PACKETFLAG_NOSEND;
2873 /* release any locks acquired before the failure */
2876 smb_SetSMBDataLength(outp, 0);
2878 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2880 lock_ReleaseMutex(&scp->mx);
2881 cm_ReleaseUser(userp);
2882 smb_ReleaseFID(fidp);
2887 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2899 fid = smb_GetSMBParm(inp, 0);
2900 fid = smb_ChainFID(fid, inp);
2902 fidp = smb_FindFID(vcp, fid, 0);
2903 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2904 return CM_ERROR_BADFD;
2907 userp = smb_GetUser(vcp, inp);
2911 /* otherwise, stat the file */
2912 lock_ObtainMutex(&scp->mx);
2913 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2914 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2915 if (code) goto done;
2917 /* decode times. We need a search time, but the response to this
2918 * call provides the date first, not the time, as returned in the
2919 * searchTime variable. So we take the high-order bits first.
2921 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2922 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
2923 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2924 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
2925 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2926 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
2927 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2929 /* now handle file size and allocation size */
2930 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
2931 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2932 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
2933 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2935 /* file attribute */
2936 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2938 /* and finalize stuff */
2939 smb_SetSMBDataLength(outp, 0);
2943 lock_ReleaseMutex(&scp->mx);
2944 cm_ReleaseUser(userp);
2945 smb_ReleaseFID(fidp);
2949 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2963 fid = smb_GetSMBParm(inp, 0);
2964 fid = smb_ChainFID(fid, inp);
2966 fidp = smb_FindFID(vcp, fid, 0);
2967 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2968 return CM_ERROR_BADFD;
2971 userp = smb_GetUser(vcp, inp);
2975 /* now prepare to call cm_setattr. This message only sets various times,
2976 * and AFS only implements mtime, and we'll set the mtime if that's
2977 * requested. The others we'll ignore.
2979 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
2981 if (searchTime != 0) {
2982 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
2984 if ( unixTime != -1 ) {
2985 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
2986 attrs.clientModTime = unixTime;
2987 code = cm_SetAttr(scp, &attrs, userp, &req);
2989 osi_Log1(afsd_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
2991 osi_Log1(afsd_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
2996 cm_ReleaseUser(userp);
2997 smb_ReleaseFID(fidp);
3002 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3005 long count, finalCount;
3012 fd = smb_GetSMBParm(inp, 2);
3013 count = smb_GetSMBParm(inp, 5);
3014 offset.HighPart = 0; /* too bad */
3015 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
3017 osi_Log3(afsd_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
3018 fd, offset.LowPart, count);
3020 fd = smb_ChainFID(fd, inp);
3021 fidp = smb_FindFID(vcp, fd, 0);
3023 return CM_ERROR_BADFD;
3025 /* set inp->fid so that later read calls in same msg can find fid */
3028 if (fidp->flags & SMB_FID_IOCTL) {
3029 return smb_IoctlV3Read(fidp, vcp, inp, outp);
3032 userp = smb_GetUser(vcp, inp);
3034 /* 0 and 1 are reserved for request chaining, were setup by our caller,
3035 * and will be further filled in after we return.
3037 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
3038 smb_SetSMBParm(outp, 3, 0); /* resvd */
3039 smb_SetSMBParm(outp, 4, 0); /* resvd */
3040 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
3041 /* fill in #6 when we have all the parameters' space reserved */
3042 smb_SetSMBParm(outp, 7, 0); /* resv'd */
3043 smb_SetSMBParm(outp, 8, 0); /* resv'd */
3044 smb_SetSMBParm(outp, 9, 0); /* resv'd */
3045 smb_SetSMBParm(outp, 10, 0); /* resv'd */
3046 smb_SetSMBParm(outp, 11, 0); /* reserved */
3048 /* get op ptr after putting in the parms, since otherwise we don't
3049 * know where the data really is.
3051 op = smb_GetSMBData(outp, NULL);
3053 /* now fill in offset from start of SMB header to first data byte (to op) */
3054 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
3056 /* set the packet data length the count of the # of bytes */
3057 smb_SetSMBDataLength(outp, count);
3060 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
3062 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
3065 /* fix some things up */
3066 smb_SetSMBParm(outp, 5, finalCount);
3067 smb_SetSMBDataLength(outp, finalCount);
3069 smb_ReleaseFID(fidp);
3071 cm_ReleaseUser(userp);
3076 * Values for createDisp, copied from NTDDK.H
3078 * FILE_SUPERSEDE 0 (???)
3079 * FILE_OPEN 1 (open)
3080 * FILE_CREATE 2 (exclusive)
3081 * FILE_OPEN_IF 3 (non-exclusive)
3082 * FILE_OVERWRITE 4 (open & truncate, but do not create)
3083 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
3086 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3088 char *pathp, *realPathp;
3092 cm_scache_t *dscp; /* parent dir */
3093 cm_scache_t *scp; /* file to create or open */
3097 unsigned short nameLength;
3099 unsigned int requestOpLock;
3100 unsigned int requestBatchOpLock;
3101 unsigned int mustBeDir;
3102 unsigned int treeCreate;
3104 unsigned int desiredAccess;
3105 unsigned int extAttributes;
3106 unsigned int createDisp;
3107 unsigned int createOptions;
3108 int initialModeBits;
3109 unsigned short baseFid;
3110 smb_fid_t *baseFidp;
3112 cm_scache_t *baseDirp;
3113 unsigned short openAction;
3128 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3129 flags = smb_GetSMBOffsetParm(inp, 3, 1)
3130 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3131 requestOpLock = flags & 0x02;
3132 requestBatchOpLock = flags & 0x04;
3133 mustBeDir = flags & 0x08;
3136 * Why all of a sudden 32-bit FID?
3137 * We will reject all bits higher than 16.
3139 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3140 return CM_ERROR_INVAL;
3141 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3142 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3143 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3144 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3145 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3146 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3147 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3148 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3149 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3151 /* mustBeDir is never set; createOptions directory bit seems to be
3154 if (createOptions & 1)
3156 else if (createOptions & 0x40)
3162 * compute initial mode bits based on read-only flag in
3163 * extended attributes
3165 initialModeBits = 0666;
3166 if (extAttributes & 1) initialModeBits &= ~0222;
3168 pathp = smb_GetSMBData(inp, NULL);
3169 /* Sometimes path is not null-terminated, so we make a copy. */
3170 realPathp = malloc(nameLength+1);
3171 memcpy(realPathp, pathp, nameLength);
3172 realPathp[nameLength] = 0;
3174 spacep = inp->spacep;
3175 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3177 osi_Log1(afsd_logp,"NTCreateX for [%s]",osi_LogSaveString(afsd_logp,realPathp));
3178 osi_Log4(afsd_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
3180 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3181 /* special case magic file name for receiving IOCTL requests
3182 * (since IOCTL calls themselves aren't getting through).
3184 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3185 smb_SetupIoctlFid(fidp, spacep);
3187 /* set inp->fid so that later read calls in same msg can find fid */
3188 inp->fid = fidp->fid;
3192 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3193 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3194 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3196 memset(&ft, 0, sizeof(ft));
3197 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3198 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3199 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3200 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3201 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3202 sz.HighPart = 0x7fff; sz.LowPart = 0;
3203 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3204 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3205 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3206 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3207 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
3208 smb_SetSMBDataLength(outp, 0);
3210 /* clean up fid reference */
3211 smb_ReleaseFID(fidp);
3216 #ifdef DEBUG_VERBOSE
3218 char *hexp, *asciip;
3219 asciip = (lastNamep? lastNamep : realPathp);
3220 hexp = osi_HexifyString( asciip );
3221 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
3225 userp = smb_GetUser(vcp, inp);
3227 osi_Log1(afsd_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
3229 return CM_ERROR_INVAL;
3233 baseDirp = cm_rootSCachep;
3234 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3237 baseFidp = smb_FindFID(vcp, baseFid, 0);
3239 osi_Log1(afsd_logp, "NTCreateX Invalid base fid [%d]", baseFid);
3241 cm_ReleaseUser(userp);
3242 return CM_ERROR_INVAL;
3244 baseDirp = baseFidp->scp;
3248 osi_Log1(afsd_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(afsd_logp,tidPathp));
3250 /* compute open mode */
3252 if (desiredAccess & DELETE)
3253 fidflags |= SMB_FID_OPENDELETE;
3254 if (desiredAccess & AFS_ACCESS_READ)
3255 fidflags |= SMB_FID_OPENREAD;
3256 if (desiredAccess & AFS_ACCESS_WRITE)
3257 fidflags |= SMB_FID_OPENWRITE;
3261 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3262 userp, tidPathp, &req, &scp);
3263 if (code == 0) foundscp = TRUE;
3265 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3266 /* look up parent directory */
3267 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
3268 the immediate parent. We have to work our way up realPathp until we hit something that we
3275 code = cm_NameI(baseDirp, spacep->data,
3276 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3277 userp, tidPathp, &req, &dscp);
3280 (tp = strrchr(spacep->data,'\\')) &&
3281 (createDisp == 2) &&
3282 (realDirFlag == 1)) {
3285 treeStartp = realPathp + (tp - spacep->data);
3287 if (*tp && !smb_IsLegalFilename(tp)) {
3288 if(baseFid != 0) smb_ReleaseFID(baseFidp);
3289 cm_ReleaseUser(userp);
3291 return CM_ERROR_BADNTFILENAME;
3298 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3301 osi_Log0(afsd_logp,"NTCreateX parent not found");
3302 cm_ReleaseUser(userp);
3307 if(treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
3308 /* A file exists where we want a directory. */
3309 cm_ReleaseSCache(dscp);
3310 cm_ReleaseUser(userp);
3312 return CM_ERROR_EXISTS;
3315 if (!lastNamep) lastNamep = realPathp;
3318 if (!smb_IsLegalFilename(lastNamep)) {
3319 cm_ReleaseSCache(dscp);
3320 cm_ReleaseUser(userp);
3322 return CM_ERROR_BADNTFILENAME;
3325 if (!foundscp && !treeCreate) {
3326 code = cm_Lookup(dscp, lastNamep,
3327 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3329 if (code && code != CM_ERROR_NOSUCHFILE) {
3330 cm_ReleaseSCache(dscp);
3331 cm_ReleaseUser(userp);
3338 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3341 /* if we get here, if code is 0, the file exists and is represented by
3342 * scp. Otherwise, we have to create it. The dir may be represented
3343 * by dscp, or we may have found the file directly. If code is non-zero,
3346 if (code == 0 && !treeCreate) {
3347 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3350 if (dscp) cm_ReleaseSCache(dscp);
3351 cm_ReleaseSCache(scp);
3352 cm_ReleaseUser(userp);
3357 if (createDisp == 2) {
3358 /* oops, file shouldn't be there */
3359 if (dscp) cm_ReleaseSCache(dscp);
3360 cm_ReleaseSCache(scp);
3361 cm_ReleaseUser(userp);
3363 return CM_ERROR_EXISTS;
3367 || createDisp == 5) {
3368 setAttr.mask = CM_ATTRMASK_LENGTH;
3369 setAttr.length.LowPart = 0;
3370 setAttr.length.HighPart = 0;
3371 code = cm_SetAttr(scp, &setAttr, userp, &req);
3372 openAction = 3; /* truncated existing file */
3374 else openAction = 1; /* found existing file */
3376 else if (createDisp == 1 || createDisp == 4) {
3377 /* don't create if not found */
3378 if (dscp) cm_ReleaseSCache(dscp);
3379 cm_ReleaseUser(userp);
3381 return CM_ERROR_NOSUCHFILE;
3383 else if (realDirFlag == 0 || realDirFlag == -1) {
3384 osi_assert(dscp != NULL);
3385 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating file %s",
3386 osi_LogSaveString(afsd_logp, lastNamep));
3387 openAction = 2; /* created file */
3388 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3389 setAttr.clientModTime = time(NULL);
3390 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3392 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3393 smb_NotifyChange(FILE_ACTION_ADDED,
3394 FILE_NOTIFY_CHANGE_FILE_NAME,
3395 dscp, lastNamep, NULL, TRUE);
3396 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3397 /* Not an exclusive create, and someone else tried
3398 * creating it already, then we open it anyway. We
3399 * don't bother retrying after this, since if this next
3400 * fails, that means that the file was deleted after we
3401 * started this call.
3403 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3406 if (createDisp == 5) {
3407 setAttr.mask = CM_ATTRMASK_LENGTH;
3408 setAttr.length.LowPart = 0;
3409 setAttr.length.HighPart = 0;
3410 code = cm_SetAttr(scp, &setAttr, userp,
3413 } /* lookup succeeded */
3418 char *cp; /* This component */
3419 int clen = 0; /* length of component */
3423 /* create directory */
3424 if ( !treeCreate ) treeStartp = lastNamep;
3425 osi_assert(dscp != NULL);
3426 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating directory [%s]",
3427 osi_LogSaveString(afsd_logp, treeStartp));
3428 openAction = 2; /* created directory */
3430 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3431 setAttr.clientModTime = time(NULL);
3438 tp = strchr(pp, '\\');
3442 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
3446 strncpy(cp,pp,clen);
3452 if(clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
3454 /* cp is the next component to be created. */
3455 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
3456 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
3457 smb_NotifyChange(FILE_ACTION_ADDED,
3458 FILE_NOTIFY_CHANGE_DIR_NAME,
3459 tscp, cp, NULL, TRUE);
3461 (code == CM_ERROR_EXISTS && createDisp != 2)) {
3462 /* Not an exclusive create, and someone else tried
3463 * creating it already, then we open it anyway. We
3464 * don't bother retrying after this, since if this next
3465 * fails, that means that the file was deleted after we
3466 * started this call.
3468 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
3473 if(!isLast) { /* for anything other than dscp, release it unless it's the last one */
3474 cm_ReleaseSCache(tscp);
3475 tscp = scp; /* Newly created directory will be next parent */
3480 if we get here and code == 0, then scp is the last directory created, and tscp is the
3481 parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
3487 /* something went wrong creating or truncating the file */
3488 if (scp) cm_ReleaseSCache(scp);
3489 if (dscp) cm_ReleaseSCache(dscp);
3490 cm_ReleaseUser(userp);
3495 /* make sure we have file vs. dir right (only applies for single component case) */
3496 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3497 cm_ReleaseSCache(scp);
3498 if (dscp) cm_ReleaseSCache(dscp);
3499 cm_ReleaseUser(userp);
3501 return CM_ERROR_ISDIR;
3503 /* (only applies to single component case) */
3504 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3505 cm_ReleaseSCache(scp);
3506 if (dscp) cm_ReleaseSCache(dscp);
3507 cm_ReleaseUser(userp);
3509 return CM_ERROR_NOTDIR;
3512 /* open the file itself */
3513 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3515 /* save a pointer to the vnode */
3518 fidp->flags = fidflags;
3520 /* save parent dir and pathname for delete or change notification */
3521 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3522 fidp->flags |= SMB_FID_NTOPEN;
3523 fidp->NTopen_dscp = dscp;
3524 cm_HoldSCache(dscp);
3525 fidp->NTopen_pathp = strdup(lastNamep);
3527 fidp->NTopen_wholepathp = realPathp;
3529 /* we don't need this any longer */
3530 if (dscp) cm_ReleaseSCache(dscp);
3531 cm_Open(scp, 0, userp);
3533 /* set inp->fid so that later read calls in same msg can find fid */
3534 inp->fid = fidp->fid;
3538 lock_ObtainMutex(&scp->mx);
3539 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3540 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3541 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3542 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3543 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3544 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3545 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3546 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3547 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3549 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3550 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3551 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3552 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3553 smb_SetSMBParmByte(outp, parmSlot,
3554 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3555 lock_ReleaseMutex(&scp->mx);
3556 smb_SetSMBDataLength(outp, 0);
3558 osi_Log2(afsd_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3559 osi_LogSaveString(afsd_logp, realPathp));
3561 smb_ReleaseFID(fidp);
3563 cm_ReleaseUser(userp);
3565 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
3567 /* leave scp held since we put it in fidp->scp */
3572 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3573 * Instead, ultimately, would like to use a subroutine for common code.
3575 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3577 char *pathp, *realPathp;
3581 cm_scache_t *dscp; /* parent dir */
3582 cm_scache_t *scp; /* file to create or open */
3585 unsigned long nameLength;
3587 unsigned int requestOpLock;
3588 unsigned int requestBatchOpLock;
3589 unsigned int mustBeDir;
3590 unsigned int extendedRespRequired;
3592 unsigned int desiredAccess;
3593 #ifdef DEBUG_VERBOSE
3594 unsigned int allocSize;
3595 unsigned int shareAccess;
3597 unsigned int extAttributes;
3598 unsigned int createDisp;
3599 #ifdef DEBUG_VERBOSE
3602 unsigned int createOptions;
3603 int initialModeBits;
3604 unsigned short baseFid;
3605 smb_fid_t *baseFidp;
3607 cm_scache_t *baseDirp;
3608 unsigned short openAction;
3614 int parmOffset, dataOffset;
3625 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3626 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3627 parmp = inp->data + parmOffset;
3628 lparmp = (ULONG *) parmp;
3631 requestOpLock = flags & 0x02;
3632 requestBatchOpLock = flags & 0x04;
3633 mustBeDir = flags & 0x08;
3634 extendedRespRequired = flags & 0x10;
3637 * Why all of a sudden 32-bit FID?
3638 * We will reject all bits higher than 16.
3640 if (lparmp[1] & 0xFFFF0000)
3641 return CM_ERROR_INVAL;
3642 baseFid = (unsigned short)lparmp[1];
3643 desiredAccess = lparmp[2];
3644 #ifdef DEBUG_VERBOSE
3645 allocSize = lparmp[3];
3646 #endif /* DEBUG_VERSOSE */
3647 extAttributes = lparmp[5];
3649 shareAccess = lparmp[6];
3651 createDisp = lparmp[7];
3652 createOptions = lparmp[8];
3653 #ifdef DEBUG_VERBOSE
3656 nameLength = lparmp[11];
3658 #ifdef DEBUG_VERBOSE
3659 osi_Log4(afsd_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
3660 osi_Log2(afsd_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
3661 osi_Log1(afsd_logp,"... flags[%x]",flags);
3664 /* mustBeDir is never set; createOptions directory bit seems to be
3667 if (createOptions & 1)
3669 else if (createOptions & 0x40)
3675 * compute initial mode bits based on read-only flag in
3676 * extended attributes
3678 initialModeBits = 0666;
3679 if (extAttributes & 1) initialModeBits &= ~0222;
3681 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3682 /* Sometimes path is not null-terminated, so we make a copy. */
3683 realPathp = malloc(nameLength+1);
3684 memcpy(realPathp, pathp, nameLength);
3685 realPathp[nameLength] = 0;
3687 spacep = cm_GetSpace();
3688 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3691 * Nothing here to handle SMB_IOCTL_FILENAME.
3692 * Will add it if necessary.
3695 #ifdef DEBUG_VERBOSE
3697 char *hexp, *asciip;
3698 asciip = (lastNamep? lastNamep : realPathp);
3699 hexp = osi_HexifyString( asciip );
3700 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
3705 userp = smb_GetUser(vcp, inp);
3707 osi_Log1(afsd_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
3709 return CM_ERROR_INVAL;
3713 baseDirp = cm_rootSCachep;
3714 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3717 baseFidp = smb_FindFID(vcp, baseFid, 0);
3719 osi_Log1(afsd_logp, "NTTranCreate Invalid fid [%d]", baseFid);
3721 cm_ReleaseUser(userp);
3722 return CM_ERROR_INVAL;
3724 baseDirp = baseFidp->scp;
3728 /* compute open mode */
3730 if (desiredAccess & DELETE)
3731 fidflags |= SMB_FID_OPENDELETE;
3732 if (desiredAccess & AFS_ACCESS_READ)
3733 fidflags |= SMB_FID_OPENREAD;
3734 if (desiredAccess & AFS_ACCESS_WRITE)
3735 fidflags |= SMB_FID_OPENWRITE;
3739 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3740 userp, tidPathp, &req, &scp);
3741 if (code == 0) foundscp = TRUE;
3743 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3744 /* look up parent directory */
3745 code = cm_NameI(baseDirp, spacep->data,
3746 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3747 userp, tidPathp, &req, &dscp);
3748 cm_FreeSpace(spacep);
3751 smb_ReleaseFID(baseFidp);
3756 cm_ReleaseUser(userp);
3761 if (!lastNamep) lastNamep = realPathp;
3764 if (!smb_IsLegalFilename(lastNamep))
3765 return CM_ERROR_BADNTFILENAME;
3768 code = cm_Lookup(dscp, lastNamep,
3769 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3771 if (code && code != CM_ERROR_NOSUCHFILE) {
3772 cm_ReleaseSCache(dscp);
3773 cm_ReleaseUser(userp);
3781 smb_ReleaseFID(baseFidp);
3784 cm_FreeSpace(spacep);
3787 /* if we get here, if code is 0, the file exists and is represented by
3788 * scp. Otherwise, we have to create it. The dir may be represented
3789 * by dscp, or we may have found the file directly. If code is non-zero,
3793 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3796 if (dscp) cm_ReleaseSCache(dscp);
3797 cm_ReleaseSCache(scp);
3798 cm_ReleaseUser(userp);
3803 if (createDisp == 2) {
3804 /* oops, file shouldn't be there */
3805 if (dscp) cm_ReleaseSCache(dscp);
3806 cm_ReleaseSCache(scp);
3807 cm_ReleaseUser(userp);
3809 return CM_ERROR_EXISTS;
3813 || createDisp == 5) {
3814 setAttr.mask = CM_ATTRMASK_LENGTH;
3815 setAttr.length.LowPart = 0;
3816 setAttr.length.HighPart = 0;
3817 code = cm_SetAttr(scp, &setAttr, userp, &req);
3818 openAction = 3; /* truncated existing file */
3820 else openAction = 1; /* found existing file */
3822 else if (createDisp == 1 || createDisp == 4) {
3823 /* don't create if not found */
3824 if (dscp) cm_ReleaseSCache(dscp);
3825 cm_ReleaseUser(userp);
3827 return CM_ERROR_NOSUCHFILE;
3829 else if (realDirFlag == 0 || realDirFlag == -1) {
3830 osi_assert(dscp != NULL);
3831 osi_Log1(afsd_logp, "smb_ReceiveNTTranCreate creating file %s",
3832 osi_LogSaveString(afsd_logp, lastNamep));
3833 openAction = 2; /* created file */
3834 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3835 setAttr.clientModTime = time(NULL);
3836 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3838 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3839 smb_NotifyChange(FILE_ACTION_ADDED,
3840 FILE_NOTIFY_CHANGE_FILE_NAME,
3841 dscp, lastNamep, NULL, TRUE);
3842 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3843 /* Not an exclusive create, and someone else tried
3844 * creating it already, then we open it anyway. We
3845 * don't bother retrying after this, since if this next
3846 * fails, that means that the file was deleted after we
3847 * started this call.
3849 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3852 if (createDisp == 5) {
3853 setAttr.mask = CM_ATTRMASK_LENGTH;
3854 setAttr.length.LowPart = 0;
3855 setAttr.length.HighPart = 0;