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 == '*') return 1;
99 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
102 /* skip over null-terminated string */
103 *chainpp = inp + strlen(inp) + 1;
108 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
111 char *usern, *pwd, *pwdx;
113 unsigned short newUid;
119 /* Check for bad conns */
120 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
121 return CM_ERROR_REMOTECONN;
123 /* For NT LM 0.12 and up, get capabilities */
124 if (vcp->flags & SMB_VCFLAG_USENT) {
125 caps = smb_GetSMBParm(inp, 11);
127 vcp->flags |= SMB_VCFLAG_STATUS32;
128 /* for now, ignore other capability bits */
132 tp = smb_GetSMBData(inp, NULL);
133 if (vcp->flags & SMB_VCFLAG_USENT)
134 pwdx = smb_ParseString(tp, &tp);
135 pwd = smb_ParseString(tp, &tp);
136 usern = smb_ParseString(tp, &tp);
138 /* On Windows 2000, this function appears to be called more often than
139 it is expected to be called. This resulted in multiple smb_user_t
140 records existing all for the same user session which results in all
141 of the users tokens disappearing.
143 To avoid this problem, we look for an existing smb_user_t record
144 based on the users name, and use that one if we find it.
147 uidp = smb_FindUserByNameThisSession(vcp, usern);
148 if (uidp) { /* already there, so don't create a new one */
151 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
152 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,usern);
153 osi_Log3(afsd_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
154 smb_ReleaseUID(uidp);
157 /* do a global search for the username/machine name pair */
158 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
160 /* Create a new UID and cm_user_t structure */
163 userp = cm_NewUser();
164 lock_ObtainMutex(&vcp->mx);
165 if (!vcp->uidCounter)
166 vcp->uidCounter++; /* handle unlikely wraparounds */
167 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
168 lock_ReleaseMutex(&vcp->mx);
170 /* Create a new smb_user_t structure and connect them up */
171 lock_ObtainMutex(&unp->mx);
173 lock_ReleaseMutex(&unp->mx);
175 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
176 lock_ObtainMutex(&uidp->mx);
178 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",(int)vcp,vcp->lana,vcp->lsn,newUid,usern);
179 osi_Log4(afsd_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
180 lock_ReleaseMutex(&uidp->mx);
181 smb_ReleaseUID(uidp);
184 /* Return UID to the client */
185 ((smb_t *)outp)->uid = newUid;
186 /* Also to the next chained message */
187 ((smb_t *)inp)->uid = newUid;
189 osi_Log3(afsd_logp, "SMB3 session setup name %s creating ID %d%s",
190 osi_LogSaveString(afsd_logp, usern), newUid, osi_LogSaveString(afsd_logp, s1));
191 smb_SetSMBParm(outp, 2, 0);
192 smb_SetSMBDataLength(outp, 0);
196 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
200 /* don't get tokens from this VC */
201 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
203 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
205 /* find the tree and free it */
206 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
207 /* TODO: smb_ReleaseUID() ? */
209 char *s1 = NULL, *s2 = NULL;
211 if (s2 == NULL) s2 = " ";
212 if (s1 == NULL) {s1 = s2; s2 = " ";}
214 osi_Log4(afsd_logp, "SMB3 user logoffX uid %d name %s%s%s",
216 osi_LogSaveString(afsd_logp,
217 (uidp->unp) ? uidp->unp->name: " "), s1, s2);
219 lock_ObtainMutex(&uidp->mx);
220 uidp->flags |= SMB_USERFLAG_DELETE;
222 * it doesn't get deleted right away
223 * because the vcp points to it
225 lock_ReleaseMutex(&uidp->mx);
228 osi_Log0(afsd_logp, "SMB3 user logoffX");
230 smb_SetSMBDataLength(outp, 0);
234 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
237 unsigned short newTid;
247 osi_Log0(afsd_logp, "SMB3 receive tree connect");
249 /* parse input parameters */
250 tp = smb_GetSMBData(inp, NULL);
251 passwordp = smb_ParseString(tp, &tp);
252 pathp = smb_ParseString(tp, &tp);
253 servicep = smb_ParseString(tp, &tp);
255 tp = strrchr(pathp, '\\');
257 return CM_ERROR_BADSMB;
259 strcpy(shareName, tp+1);
261 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0)
262 return CM_ERROR_NOIPC;
264 userp = smb_GetUser(vcp, inp);
266 lock_ObtainMutex(&vcp->mx);
267 newTid = vcp->tidCounter++;
268 lock_ReleaseMutex(&vcp->mx);
270 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
271 shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
273 smb_ReleaseTID(tidp);
274 return CM_ERROR_BADSHARENAME;
276 lock_ObtainMutex(&tidp->mx);
278 tidp->pathname = sharePath;
279 lock_ReleaseMutex(&tidp->mx);
280 smb_ReleaseTID(tidp);
282 if (vcp->flags & SMB_VCFLAG_USENT)
283 smb_SetSMBParm(outp, 2, 0); /* OptionalSupport bits */
285 ((smb_t *)outp)->tid = newTid;
286 ((smb_t *)inp)->tid = newTid;
287 tp = smb_GetSMBData(outp, NULL);
291 smb_SetSMBDataLength(outp, 3);
293 osi_Log1(afsd_logp, "SMB3 tree connect created ID %d", newTid);
297 /* must be called with global tran lock held */
298 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
300 smb_tran2Packet_t *tp;
303 smbp = (smb_t *) inp->data;
304 for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
305 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
311 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
312 int totalParms, int totalData)
314 smb_tran2Packet_t *tp;
317 smbp = (smb_t *) inp->data;
318 tp = malloc(sizeof(*tp));
319 memset(tp, 0, sizeof(*tp));
322 tp->curData = tp->curParms = 0;
323 tp->totalData = totalData;
324 tp->totalParms = totalParms;
329 tp->res[0] = smbp->res[0];
330 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
331 tp->opcode = smb_GetSMBParm(inp, 14);
333 tp->parmsp = malloc(totalParms);
335 tp->datap = malloc(totalData);
336 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
340 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
341 smb_tran2Packet_t *inp, smb_packet_t *outp,
342 int totalParms, int totalData)
344 smb_tran2Packet_t *tp;
345 unsigned short parmOffset;
346 unsigned short dataOffset;
347 unsigned short dataAlign;
349 tp = malloc(sizeof(*tp));
350 memset(tp, 0, sizeof(*tp));
352 tp->curData = tp->curParms = 0;
353 tp->totalData = totalData;
354 tp->totalParms = totalParms;
355 tp->oldTotalParms = totalParms;
360 tp->res[0] = inp->res[0];
361 tp->opcode = inp->opcode;
364 * We calculate where the parameters and data will start.
365 * This calculation must parallel the calculation in
366 * smb_SendTran2Packet.
369 parmOffset = 10*2 + 35;
370 parmOffset++; /* round to even */
371 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
373 dataOffset = parmOffset + totalParms;
374 dataAlign = dataOffset & 2; /* quad-align */
375 dataOffset += dataAlign;
376 tp->datap = outp->data + dataOffset;
381 /* free a tran2 packet; must be called with smb_globalLock held */
382 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
384 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
385 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
394 /* called with a VC, an input packet to respond to, and an error code.
395 * sends an error response.
397 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
398 smb_packet_t *tp, long code)
401 unsigned short errCode;
402 unsigned char errClass;
403 unsigned long NTStatus;
405 if (vcp->flags & SMB_VCFLAG_STATUS32)
406 smb_MapNTError(code, &NTStatus);
408 smb_MapCoreError(code, vcp, &errCode, &errClass);
410 smb_FormatResponsePacket(vcp, NULL, tp);
413 /* We can handle long names */
414 if (vcp->flags & SMB_VCFLAG_USENT)
415 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
417 /* now copy important fields from the tran 2 packet */
418 smbp->com = 0x32; /* tran 2 response */
419 smbp->tid = t2p->tid;
420 smbp->mid = t2p->mid;
421 smbp->pid = t2p->pid;
422 smbp->uid = t2p->uid;
423 smbp->res[0] = t2p->res[0];
424 if (vcp->flags & SMB_VCFLAG_STATUS32) {
425 smbp->rcls = (unsigned char) (NTStatus & 0xff);
426 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
427 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
428 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
429 smbp->flg2 |= 0x4000;
432 smbp->rcls = errClass;
433 smbp->errLow = (unsigned char) (errCode & 0xff);
434 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
438 smb_SendPacket(vcp, tp);
441 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
444 unsigned short parmOffset;
445 unsigned short dataOffset;
446 unsigned short totalLength;
447 unsigned short dataAlign;
450 smb_FormatResponsePacket(vcp, NULL, tp);
453 /* We can handle long names */
454 if (vcp->flags & SMB_VCFLAG_USENT)
455 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
457 /* now copy important fields from the tran 2 packet */
458 smbp->com = 0x32; /* tran 2 response */
459 smbp->tid = t2p->tid;
460 smbp->mid = t2p->mid;
461 smbp->pid = t2p->pid;
462 smbp->uid = t2p->uid;
463 smbp->res[0] = t2p->res[0];
465 totalLength = 1 + t2p->totalData + t2p->totalParms;
467 /* now add the core parameters (tran2 info) to the packet */
468 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
469 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
470 smb_SetSMBParm(tp, 2, 0); /* reserved */
471 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
472 parmOffset = 10*2 + 35; /* parm offset in packet */
473 parmOffset++; /* round to even */
474 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
475 * hdr, bcc and wct */
476 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
477 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
478 dataOffset = parmOffset + t2p->oldTotalParms;
479 dataAlign = dataOffset & 2; /* quad-align */
480 dataOffset += dataAlign;
481 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
482 smb_SetSMBParm(tp, 8, 0); /* data displacement */
483 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
486 datap = smb_GetSMBData(tp, NULL);
487 *datap++ = 0; /* we rounded to even */
489 totalLength += dataAlign;
490 smb_SetSMBDataLength(tp, totalLength);
492 /* next, send the datagram */
493 smb_SendPacket(vcp, tp);
496 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
498 smb_tran2Packet_t *asp;
510 /* We sometimes see 0 word count. What to do? */
511 if (*inp->wctp == 0) {
516 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0");
518 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
519 ptbuf[0] = "Transaction2 word count = 0";
520 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
521 1, inp->ncb_length, ptbuf, inp);
522 DeregisterEventSource(h);
524 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0");
527 smb_SetSMBDataLength(outp, 0);
528 smb_SendPacket(vcp, outp);
532 totalParms = smb_GetSMBParm(inp, 0);
533 totalData = smb_GetSMBParm(inp, 1);
535 firstPacket = (inp->inCom == 0x32);
537 /* find the packet we're reassembling */
538 lock_ObtainWrite(&smb_globalLock);
539 asp = smb_FindTran2Packet(vcp, inp);
541 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
543 lock_ReleaseWrite(&smb_globalLock);
545 /* now merge in this latest packet; start by looking up offsets */
547 parmDisp = dataDisp = 0;
548 parmOffset = smb_GetSMBParm(inp, 10);
549 dataOffset = smb_GetSMBParm(inp, 12);
550 parmCount = smb_GetSMBParm(inp, 9);
551 dataCount = smb_GetSMBParm(inp, 11);
552 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
553 asp->maxReturnData = smb_GetSMBParm(inp, 3);
555 osi_Log3(afsd_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
556 totalData, dataCount, asp->maxReturnData);
559 parmDisp = smb_GetSMBParm(inp, 4);
560 parmOffset = smb_GetSMBParm(inp, 3);
561 dataDisp = smb_GetSMBParm(inp, 7);
562 dataOffset = smb_GetSMBParm(inp, 6);
563 parmCount = smb_GetSMBParm(inp, 2);
564 dataCount = smb_GetSMBParm(inp, 5);
566 osi_Log2(afsd_logp, "SMB3 received T2 aux packet parms %d, data %d",
567 parmCount, dataCount);
570 /* now copy the parms and data */
571 if ( parmCount != 0 )
573 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
575 if ( dataCount != 0 ) {
576 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
579 /* account for new bytes */
580 asp->curData += dataCount;
581 asp->curParms += parmCount;
583 /* finally, if we're done, remove the packet from the queue and dispatch it */
584 if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
585 /* we've received it all */
586 lock_ObtainWrite(&smb_globalLock);
587 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
588 lock_ReleaseWrite(&smb_globalLock);
590 /* now dispatch it */
591 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
592 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
593 osi_Log4(afsd_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
594 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
597 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
598 osi_Log4(afsd_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
599 code = CM_ERROR_BADOP;
602 /* if an error is returned, we're supposed to send an error packet,
603 * otherwise the dispatched function already did the data sending.
604 * We give dispatched proc the responsibility since it knows how much
608 smb_SendTran2Error(vcp, asp, outp, code);
611 /* free the input tran 2 packet */
612 lock_ObtainWrite(&smb_globalLock);
613 smb_FreeTran2Packet(asp);
614 lock_ReleaseWrite(&smb_globalLock);
616 else if (firstPacket) {
617 /* the first packet in a multi-packet request, we need to send an
618 * ack to get more data.
620 smb_SetSMBDataLength(outp, 0);
621 smb_SendPacket(vcp, outp);
627 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
630 smb_tran2Packet_t *outp;
635 cm_scache_t *dscp; /* dir we're dealing with */
636 cm_scache_t *scp; /* file we're creating */
648 int parmSlot; /* which parm we're dealing with */
657 extraInfo = (p->parmsp[0] & 1); /* return extra info */
658 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
660 openFun = p->parmsp[6]; /* open function */
661 excl = ((openFun & 3) == 0);
662 trunc = ((openFun & 3) == 2); /* truncate it */
663 openMode = (p->parmsp[1] & 0x7);
664 openAction = 0; /* tracks what we did */
666 attributes = p->parmsp[3];
667 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
669 /* compute initial mode bits based on read-only flag in attributes */
670 initialModeBits = 0666;
671 if (attributes & 1) initialModeBits &= ~0222;
673 pathp = (char *) (&p->parmsp[14]);
675 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
677 spacep = cm_GetSpace();
678 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
680 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
681 /* special case magic file name for receiving IOCTL requests
682 * (since IOCTL calls themselves aren't getting through).
684 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
685 smb_SetupIoctlFid(fidp, spacep);
687 /* copy out remainder of the parms */
689 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
691 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
692 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
693 outp->parmsp[parmSlot] = 0; parmSlot++;
694 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
695 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
696 outp->parmsp[parmSlot] = openMode; parmSlot++;
697 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
698 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
700 /* and the final "always present" stuff */
701 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
702 /* next write out the "unique" ID */
703 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
704 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
705 outp->parmsp[parmSlot] = 0; parmSlot++;
706 if (returnEALength) {
707 outp->parmsp[parmSlot] = 0; parmSlot++;
708 outp->parmsp[parmSlot] = 0; parmSlot++;
712 outp->totalParms = parmSlot * 2;
714 smb_SendTran2Packet(vcp, outp, op);
716 smb_FreeTran2Packet(outp);
718 /* and clean up fid reference */
719 smb_ReleaseFID(fidp);
726 asciip = (lastNamep ? lastNamep : pathp);
727 hexp = osi_HexifyString( asciip );
728 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
733 userp = smb_GetTran2User(vcp, p);
734 /* In the off chance that userp is NULL, we log and abandon */
736 osi_Log1(afsd_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
737 smb_FreeTran2Packet(outp);
738 return CM_ERROR_BADSMB;
741 tidPathp = smb_GetTIDPath(vcp, p->tid);
744 code = cm_NameI(cm_rootSCachep, pathp,
745 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
746 userp, tidPathp, &req, &scp);
748 code = cm_NameI(cm_rootSCachep, spacep->data,
749 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
750 userp, tidPathp, &req, &dscp);
751 cm_FreeSpace(spacep);
754 cm_ReleaseUser(userp);
755 smb_FreeTran2Packet(outp);
759 /* otherwise, scp points to the parent directory. Do a lookup,
760 * and truncate the file if we find it, otherwise we create the
763 if (!lastNamep) lastNamep = pathp;
765 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
767 if (code && code != CM_ERROR_NOSUCHFILE) {
768 cm_ReleaseSCache(dscp);
769 cm_ReleaseUser(userp);
770 smb_FreeTran2Packet(outp);
775 cm_FreeSpace(spacep);
778 /* if we get here, if code is 0, the file exists and is represented by
779 * scp. Otherwise, we have to create it.
782 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
784 if (dscp) cm_ReleaseSCache(dscp);
785 cm_ReleaseSCache(scp);
786 cm_ReleaseUser(userp);
787 smb_FreeTran2Packet(outp);
792 /* oops, file shouldn't be there */
793 if (dscp) cm_ReleaseSCache(dscp);
794 cm_ReleaseSCache(scp);
795 cm_ReleaseUser(userp);
796 smb_FreeTran2Packet(outp);
797 return CM_ERROR_EXISTS;
801 setAttr.mask = CM_ATTRMASK_LENGTH;
802 setAttr.length.LowPart = 0;
803 setAttr.length.HighPart = 0;
804 code = cm_SetAttr(scp, &setAttr, userp, &req);
805 openAction = 3; /* truncated existing file */
807 else openAction = 1; /* found existing file */
809 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
810 /* don't create if not found */
811 if (dscp) cm_ReleaseSCache(dscp);
812 osi_assert(scp == NULL);
813 cm_ReleaseUser(userp);
814 smb_FreeTran2Packet(outp);
815 return CM_ERROR_NOSUCHFILE;
818 osi_assert(dscp != NULL && scp == NULL);
819 openAction = 2; /* created file */
820 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
821 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
822 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
824 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
825 smb_NotifyChange(FILE_ACTION_ADDED,
826 FILE_NOTIFY_CHANGE_FILE_NAME,
827 dscp, lastNamep, NULL, TRUE);
828 if (!excl && code == CM_ERROR_EXISTS) {
829 /* not an exclusive create, and someone else tried
830 * creating it already, then we open it anyway. We
831 * don't bother retrying after this, since if this next
832 * fails, that means that the file was deleted after we
835 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
839 setAttr.mask = CM_ATTRMASK_LENGTH;
840 setAttr.length.LowPart = 0;
841 setAttr.length.HighPart = 0;
842 code = cm_SetAttr(scp, &setAttr, userp,
845 } /* lookup succeeded */
849 /* we don't need this any longer */
850 if (dscp) cm_ReleaseSCache(dscp);
853 /* something went wrong creating or truncating the file */
854 if (scp) cm_ReleaseSCache(scp);
855 cm_ReleaseUser(userp);
856 smb_FreeTran2Packet(outp);
860 /* make sure we're about to open a file */
861 if (scp->fileType != CM_SCACHETYPE_FILE) {
862 cm_ReleaseSCache(scp);
863 cm_ReleaseUser(userp);
864 smb_FreeTran2Packet(outp);
865 return CM_ERROR_ISDIR;
868 /* now all we have to do is open the file itself */
869 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
872 /* save a pointer to the vnode */
875 /* compute open mode */
876 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
877 if (openMode == 1 || openMode == 2)
878 fidp->flags |= SMB_FID_OPENWRITE;
880 smb_ReleaseFID(fidp);
882 cm_Open(scp, 0, userp);
884 /* copy out remainder of the parms */
886 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
887 lock_ObtainMutex(&scp->mx);
889 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
890 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
891 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
892 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
893 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
895 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
897 outp->parmsp[parmSlot] = openMode; parmSlot++;
898 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
899 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
901 /* and the final "always present" stuff */
902 outp->parmsp[parmSlot] = openAction; parmSlot++;
903 /* next write out the "unique" ID */
904 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
905 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
906 outp->parmsp[parmSlot] = 0; parmSlot++;
907 if (returnEALength) {
908 outp->parmsp[parmSlot] = 0; parmSlot++;
909 outp->parmsp[parmSlot] = 0; parmSlot++;
911 lock_ReleaseMutex(&scp->mx);
912 outp->totalData = 0; /* total # of data bytes */
913 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
915 smb_SendTran2Packet(vcp, outp, op);
917 smb_FreeTran2Packet(outp);
919 cm_ReleaseUser(userp);
920 /* leave scp held since we put it in fidp->scp */
924 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
926 return CM_ERROR_BADOP;
929 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
931 return CM_ERROR_BADOP;
934 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
936 smb_tran2Packet_t *outp;
937 smb_tran2QFSInfo_t qi;
940 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
942 osi_Log1(afsd_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
944 switch (p->parmsp[0]) {
945 case 1: responseSize = sizeof(qi.u.allocInfo); break;
946 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
947 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
948 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
949 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
950 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
951 default: return CM_ERROR_INVAL;
954 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
955 switch (p->parmsp[0]) {
958 qi.u.allocInfo.FSID = 0;
959 qi.u.allocInfo.sectorsPerAllocUnit = 1;
960 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
961 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
962 qi.u.allocInfo.bytesPerSector = 1024;
967 qi.u.volumeInfo.vsn = 1234;
968 qi.u.volumeInfo.vnCount = 4;
969 /* we're supposed to pad it out with zeroes to the end */
970 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
971 memcpy(qi.u.volumeInfo.label, "AFS", 4);
976 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
977 qi.u.FSvolumeInfo.vsn = 1234;
978 qi.u.FSvolumeInfo.vnCount = 8;
979 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
985 temp.LowPart = 0x7fffffff;
986 qi.u.FSsizeInfo.totalAllocUnits = temp;
987 temp.LowPart = 0x3fffffff;
988 qi.u.FSsizeInfo.availAllocUnits = temp;
989 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
990 qi.u.FSsizeInfo.bytesPerSector = 1024;
995 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
996 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
1000 /* FS attribute info */
1001 /* attributes, defined in WINNT.H:
1002 * FILE_CASE_SENSITIVE_SEARCH 0x1
1003 * FILE_CASE_PRESERVED_NAMES 0x2
1004 * <no name defined> 0x4000
1005 * If bit 0x4000 is not set, Windows 95 thinks
1006 * we can't handle long (non-8.3) names,
1007 * despite our protestations to the contrary.
1009 qi.u.FSattributeInfo.attributes = 0x4003;
1010 qi.u.FSattributeInfo.maxCompLength = 255;
1011 qi.u.FSattributeInfo.FSnameLength = 6;
1012 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
1016 /* copy out return data, and set corresponding sizes */
1017 outp->totalParms = 0;
1018 outp->totalData = responseSize;
1019 memcpy(outp->datap, &qi, responseSize);
1021 /* send and free the packets */
1022 smb_SendTran2Packet(vcp, outp, op);
1023 smb_FreeTran2Packet(outp);
1028 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1030 return CM_ERROR_BADOP;
1033 struct smb_ShortNameRock {
1037 size_t shortNameLen;
1040 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
1043 struct smb_ShortNameRock *rockp;
1047 /* compare both names and vnodes, though probably just comparing vnodes
1048 * would be safe enough.
1050 if (stricmp(dep->name, rockp->maskp) != 0)
1052 if (ntohl(dep->fid.vnode) != rockp->vnode)
1054 /* This is the entry */
1055 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1056 rockp->shortNameLen = shortNameEnd - rockp->shortName;
1057 return CM_ERROR_STOPNOW;
1060 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1061 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1063 struct smb_ShortNameRock rock;
1067 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1071 spacep = cm_GetSpace();
1072 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1074 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1076 cm_FreeSpace(spacep);
1077 if (code) return code;
1079 if (!lastNamep) lastNamep = pathp;
1082 thyper.HighPart = 0;
1083 rock.shortName = shortName;
1085 rock.maskp = lastNamep;
1086 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1089 cm_ReleaseSCache(dscp);
1092 return CM_ERROR_NOSUCHFILE;
1093 if (code == CM_ERROR_STOPNOW) {
1094 *shortNameLenp = rock.shortNameLen;
1100 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1102 smb_tran2Packet_t *outp;
1103 unsigned long dosTime;
1105 unsigned short infoLevel;
1107 unsigned short attributes;
1108 unsigned long extAttributes;
1113 cm_scache_t *scp, *dscp;
1122 infoLevel = p->parmsp[0];
1123 if (infoLevel == 6) nbytesRequired = 0;
1124 else if (infoLevel == 1) nbytesRequired = 22;
1125 else if (infoLevel == 2) nbytesRequired = 26;
1126 else if (infoLevel == 0x101) nbytesRequired = 40;
1127 else if (infoLevel == 0x102) nbytesRequired = 24;
1128 else if (infoLevel == 0x103) nbytesRequired = 4;
1129 else if (infoLevel == 0x108) nbytesRequired = 30;
1131 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1132 p->opcode, infoLevel);
1133 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1136 osi_Log2(afsd_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1137 osi_LogSaveString(afsd_logp, (char *)(&p->parmsp[3])));
1139 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1141 if (infoLevel > 0x100)
1142 outp->totalParms = 2;
1144 outp->totalParms = 0;
1145 outp->totalData = nbytesRequired;
1147 /* now, if we're at infoLevel 6, we're only being asked to check
1148 * the syntax, so we just OK things now. In particular, we're *not*
1149 * being asked to verify anything about the state of any parent dirs.
1151 if (infoLevel == 6) {
1152 smb_SendTran2Packet(vcp, outp, opx);
1153 smb_FreeTran2Packet(outp);
1157 userp = smb_GetTran2User(vcp, p);
1159 osi_Log1(afsd_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
1160 smb_FreeTran2Packet(outp);
1161 return CM_ERROR_BADSMB;
1164 tidPathp = smb_GetTIDPath(vcp, p->tid);
1167 * XXX Strange hack XXX
1169 * As of Patch 7 (13 January 98), we are having the following problem:
1170 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1171 * requests to look up "desktop.ini" in all the subdirectories.
1172 * This can cause zillions of timeouts looking up non-existent cells
1173 * and volumes, especially in the top-level directory.
1175 * We have not found any way to avoid this or work around it except
1176 * to explicitly ignore the requests for mount points that haven't
1177 * yet been evaluated and for directories that haven't yet been
1180 if (infoLevel == 0x101) {
1181 spacep = cm_GetSpace();
1182 smb_StripLastComponent(spacep->data, &lastComp,
1183 (char *)(&p->parmsp[3]));
1184 /* Make sure that lastComp is not NULL */
1186 if (strcmp(lastComp, "\\desktop.ini") == 0) {
1187 code = cm_NameI(cm_rootSCachep, spacep->data,
1191 userp, tidPathp, &req, &dscp);
1193 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1194 && !dscp->mountRootFidp)
1195 code = CM_ERROR_NOSUCHFILE;
1196 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1197 cm_buf_t *bp = buf_Find(dscp, &hzero);
1201 code = CM_ERROR_NOSUCHFILE;
1203 cm_ReleaseSCache(dscp);
1205 cm_FreeSpace(spacep);
1206 cm_ReleaseUser(userp);
1207 smb_SendTran2Error(vcp, p, opx, code);
1208 smb_FreeTran2Packet(outp);
1214 cm_FreeSpace(spacep);
1217 /* now do namei and stat, and copy out the info */
1218 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1219 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1222 cm_ReleaseUser(userp);
1223 smb_SendTran2Error(vcp, p, opx, code);
1224 smb_FreeTran2Packet(outp);
1228 lock_ObtainMutex(&scp->mx);
1229 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1230 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1231 if (code) goto done;
1233 /* now we have the status in the cache entry, and everything is locked.
1234 * Marshall the output data.
1237 /* for info level 108, figure out short name */
1238 if (infoLevel == 0x108) {
1239 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1240 tidPathp, scp->fid.vnode, shortName,
1247 *((u_long *)op) = len * 2; op += 4;
1248 mbstowcs((unsigned short *)op, shortName, len);
1253 if (infoLevel == 1 || infoLevel == 2) {
1254 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1255 *((u_long *)op) = dosTime; op += 4; /* creation time */
1256 *((u_long *)op) = dosTime; op += 4; /* access time */
1257 *((u_long *)op) = dosTime; op += 4; /* write time */
1258 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1259 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1260 attributes = smb_Attributes(scp);
1261 *((u_short *)op) = attributes; op += 2; /* attributes */
1263 else if (infoLevel == 0x101) {
1264 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1265 *((FILETIME *)op) = ft; op += 8; /* creation time */
1266 *((FILETIME *)op) = ft; op += 8; /* last access time */
1267 *((FILETIME *)op) = ft; op += 8; /* last write time */
1268 *((FILETIME *)op) = ft; op += 8; /* last change time */
1269 extAttributes = smb_ExtAttributes(scp);
1270 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1271 *((u_long *)op) = 0; op += 4; /* don't know what this is */
1273 else if (infoLevel == 0x102) {
1274 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1275 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1276 *((u_long *)op) = scp->linkCount; op += 4;
1279 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1282 else if (infoLevel == 0x103) {
1283 memset(op, 0, 4); op += 4; /* EA size */
1286 /* now, if we are being asked about extended attrs, return a 0 size */
1287 if (infoLevel == 2) {
1288 *((u_long *)op) = 0; op += 4;
1292 /* send and free the packets */
1294 lock_ReleaseMutex(&scp->mx);
1295 cm_ReleaseSCache(scp);
1296 cm_ReleaseUser(userp);
1297 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1298 else smb_SendTran2Error(vcp, p, opx, code);
1299 smb_FreeTran2Packet(outp);
1304 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1306 return CM_ERROR_BADOP;
1309 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1311 smb_tran2Packet_t *outp;
1313 unsigned long attributes;
1314 unsigned short infoLevel;
1327 fidp = smb_FindFID(vcp, fid, 0);
1330 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
1334 infoLevel = p->parmsp[1];
1335 if (infoLevel == 0x101) nbytesRequired = 40;
1336 else if (infoLevel == 0x102) nbytesRequired = 24;
1337 else if (infoLevel == 0x103) nbytesRequired = 4;
1338 else if (infoLevel == 0x104) nbytesRequired = 6;
1340 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1341 p->opcode, infoLevel);
1342 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1343 smb_ReleaseFID(fidp);
1346 osi_Log2(afsd_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1348 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1350 if (infoLevel > 0x100)
1351 outp->totalParms = 2;
1353 outp->totalParms = 0;
1354 outp->totalData = nbytesRequired;
1356 userp = smb_GetTran2User(vcp, p);
1358 osi_Log1(afsd_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
1359 code = CM_ERROR_BADSMB;
1364 lock_ObtainMutex(&scp->mx);
1365 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1366 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1367 if (code) goto done;
1369 /* now we have the status in the cache entry, and everything is locked.
1370 * Marshall the output data.
1373 if (infoLevel == 0x101) {
1374 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1375 *((FILETIME *)op) = ft; op += 8; /* creation time */
1376 *((FILETIME *)op) = ft; op += 8; /* last access time */
1377 *((FILETIME *)op) = ft; op += 8; /* last write time */
1378 *((FILETIME *)op) = ft; op += 8; /* last change time */
1379 attributes = smb_ExtAttributes(scp);
1380 *((u_long *)op) = attributes; op += 4;
1381 *((u_long *)op) = 0; op += 4;
1383 else if (infoLevel == 0x102) {
1384 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1385 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1386 *((u_long *)op) = scp->linkCount; op += 4;
1387 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1388 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1392 else if (infoLevel == 0x103) {
1393 *((u_long *)op) = 0; op += 4;
1395 else if (infoLevel == 0x104) {
1399 if (fidp->NTopen_wholepathp)
1400 name = fidp->NTopen_wholepathp;
1402 name = "\\"; /* probably can't happen */
1404 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
1405 *((u_long *)op) = len * 2; op += 4;
1406 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1409 /* send and free the packets */
1411 lock_ReleaseMutex(&scp->mx);
1412 cm_ReleaseUser(userp);
1413 smb_ReleaseFID(fidp);
1414 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1415 else smb_SendTran2Error(vcp, p, opx, code);
1416 smb_FreeTran2Packet(outp);
1421 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1426 unsigned short infoLevel;
1427 smb_tran2Packet_t *outp;
1435 fidp = smb_FindFID(vcp, fid, 0);
1438 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1442 infoLevel = p->parmsp[1];
1443 if (infoLevel > 0x104 || infoLevel < 0x101) {
1444 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1445 p->opcode, infoLevel);
1446 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1447 smb_ReleaseFID(fidp);
1451 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1452 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1453 smb_ReleaseFID(fidp);
1456 if ((infoLevel == 0x103 || infoLevel == 0x104)
1457 && !(fidp->flags & SMB_FID_OPENWRITE)) {
1458 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1459 smb_ReleaseFID(fidp);
1463 osi_Log1(afsd_logp, "T2 SFileInfo type 0x%x", infoLevel);
1465 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1467 outp->totalParms = 2;
1468 outp->totalData = 0;
1470 userp = smb_GetTran2User(vcp, p);
1472 osi_Log1(afsd_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
1473 code = CM_ERROR_BADSMB;
1479 if (infoLevel == 0x101) {
1481 unsigned int attribute;
1484 /* lock the vnode with a callback; we need the current status
1485 * to determine what the new status is, in some cases.
1487 lock_ObtainMutex(&scp->mx);
1488 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1489 CM_SCACHESYNC_GETSTATUS
1490 | CM_SCACHESYNC_NEEDCALLBACK);
1492 lock_ReleaseMutex(&scp->mx);
1496 /* prepare for setattr call */
1499 lastMod = *((FILETIME *)(p->datap + 16));
1500 /* when called as result of move a b, lastMod is (-1, -1).
1501 * If the check for -1 is not present, timestamp
1502 * of the resulting file will be 1969 (-1)
1504 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
1505 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
1506 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1507 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1509 fidp->flags |= SMB_FID_MTIMESETDONE;
1512 attribute = *((u_long *)(p->datap + 32));
1513 if (attribute != 0) {
1514 if ((scp->unixModeBits & 0222)
1515 && (attribute & 1) != 0) {
1516 /* make a writable file read-only */
1517 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1518 attr.unixModeBits = scp->unixModeBits & ~0222;
1520 else if ((scp->unixModeBits & 0222) == 0
1521 && (attribute & 1) == 0) {
1522 /* make a read-only file writable */
1523 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1524 attr.unixModeBits = scp->unixModeBits | 0222;
1527 lock_ReleaseMutex(&scp->mx);
1531 code = cm_SetAttr(scp, &attr, userp, &req);
1535 else if (infoLevel == 0x103 || infoLevel == 0x104) {
1536 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1539 attr.mask = CM_ATTRMASK_LENGTH;
1540 attr.length.LowPart = size.LowPart;
1541 attr.length.HighPart = size.HighPart;
1542 code = cm_SetAttr(scp, &attr, userp, &req);
1544 else if (infoLevel == 0x102) {
1545 if (*((char *)(p->datap))) {
1546 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1549 fidp->flags |= SMB_FID_DELONCLOSE;
1553 fidp->flags &= ~SMB_FID_DELONCLOSE;
1557 cm_ReleaseUser(userp);
1558 smb_ReleaseFID(fidp);
1559 if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1560 else smb_SendTran2Error(vcp, p, op, code);
1561 smb_FreeTran2Packet(outp);
1566 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1568 return CM_ERROR_BADOP;
1571 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1573 return CM_ERROR_BADOP;
1576 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1578 return CM_ERROR_BADOP;
1581 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1583 return CM_ERROR_BADOP;
1586 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1588 return CM_ERROR_BADOP;
1591 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1592 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1597 cm_scache_t *targetScp; /* target if scp is a symlink */
1602 unsigned short attr;
1603 unsigned long lattr;
1604 smb_dirListPatch_t *patchp;
1605 smb_dirListPatch_t *npatchp;
1607 for(patchp = *dirPatchespp; patchp; patchp =
1608 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1609 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1611 lock_ObtainMutex(&scp->mx);
1612 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1613 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1615 lock_ReleaseMutex(&scp->mx);
1616 cm_ReleaseSCache(scp);
1620 /* now watch for a symlink */
1621 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1622 lock_ReleaseMutex(&scp->mx);
1623 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp,
1626 /* we have a more accurate file to use (the
1627 * target of the symbolic link). Otherwise,
1628 * we'll just use the symlink anyway.
1630 osi_Log2(afsd_logp, "symlink vp %x to vp %x",
1632 cm_ReleaseSCache(scp);
1635 lock_ObtainMutex(&scp->mx);
1638 dptr = patchp->dptr;
1640 if (infoLevel >= 0x101) {
1642 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1644 /* copy to Creation Time */
1645 *((FILETIME *)dptr) = ft;
1648 /* copy to Last Access Time */
1649 *((FILETIME *)dptr) = ft;
1652 /* copy to Last Write Time */
1653 *((FILETIME *)dptr) = ft;
1656 /* copy to Change Time */
1657 *((FILETIME *)dptr) = ft;
1660 /* Use length for both file length and alloc length */
1661 *((LARGE_INTEGER *)dptr) = scp->length;
1663 *((LARGE_INTEGER *)dptr) = scp->length;
1666 /* Copy attributes */
1667 lattr = smb_ExtAttributes(scp);
1668 /* merge in hidden (dot file) attribute */
1669 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1670 lattr |= SMB_ATTR_HIDDEN;
1671 *((u_long *)dptr) = lattr;
1676 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1678 /* and copy out date */
1679 shortTemp = (dosTime>>16) & 0xffff;
1680 *((u_short *)dptr) = shortTemp;
1683 /* copy out creation time */
1684 shortTemp = dosTime & 0xffff;
1685 *((u_short *)dptr) = shortTemp;
1688 /* and copy out date */
1689 shortTemp = (dosTime>>16) & 0xffff;
1690 *((u_short *)dptr) = shortTemp;
1693 /* copy out access time */
1694 shortTemp = dosTime & 0xffff;
1695 *((u_short *)dptr) = shortTemp;
1698 /* and copy out date */
1699 shortTemp = (dosTime>>16) & 0xffff;
1700 *((u_short *)dptr) = shortTemp;
1703 /* copy out mod time */
1704 shortTemp = dosTime & 0xffff;
1705 *((u_short *)dptr) = shortTemp;
1708 /* copy out file length and alloc length,
1709 * using the same for both
1711 *((u_long *)dptr) = scp->length.LowPart;
1713 *((u_long *)dptr) = scp->length.LowPart;
1716 /* finally copy out attributes as short */
1717 attr = smb_Attributes(scp);
1718 /* merge in hidden (dot file) attribute */
1719 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1720 attr |= SMB_ATTR_HIDDEN;
1721 *dptr++ = attr & 0xff;
1722 *dptr++ = (attr >> 8) & 0xff;
1725 lock_ReleaseMutex(&scp->mx);
1726 cm_ReleaseSCache(scp);
1729 /* now free the patches */
1730 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1731 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1735 /* and mark the list as empty */
1736 *dirPatchespp = NULL;
1741 /* do a case-folding search of the star name mask with the name in namep.
1742 * Return 1 if we match, otherwise 0.
1744 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1746 unsigned char tcp1, tcp2; /* Pattern characters */
1747 unsigned char tcn1; /* Name characters */
1748 int sawDot = 0, sawStar = 0;
1749 char *starNamep, *starMaskp;
1750 static char nullCharp[] = {0};
1752 /* make sure we only match 8.3 names, if requested */
1753 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) return 0;
1757 /* Next pattern character */
1760 /* Next name character */
1764 /* 0 - end of pattern */
1770 else if (tcp1 == '.' || tcp1 == '"') {
1780 * first dot in pattern;
1781 * must match dot or end of name
1786 else if (tcn1 == '.') {
1795 else if (tcp1 == '?') {
1796 if (tcn1 == 0 || tcn1 == '.')
1801 else if (tcp1 == '>') {
1802 if (tcn1 != 0 && tcn1 != '.')
1806 else if (tcp1 == '*' || tcp1 == '<') {
1810 else if (tcp2 == '.' || tcp2 == '"') {
1811 while (tcn1 != '.' && tcn1 != 0)
1826 * pattern character after '*' is not null or
1827 * period. If it is '?' or '>', we are not
1828 * going to understand it. If it is '*' or
1829 * '<', we are going to skip over it. None of
1830 * these are likely, I hope.
1832 /* skip over '*' and '<' */
1833 while (tcp2 == '*' || tcp2 == '<')
1836 /* skip over characters that don't match tcp2 */
1837 while (tcn1 != '.' && tcn1 != 0
1838 && cm_foldUpper[tcn1] != cm_foldUpper[tcp2])
1842 if (tcn1 == '.' || tcn1 == 0)
1845 /* Remember where we are */
1855 /* tcp1 is not a wildcard */
1856 if (cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) {
1861 /* if trying to match a star pattern, go back */
1863 maskp = starMaskp - 2;
1864 namep = starNamep + 1;
1874 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1883 smb_dirListPatch_t *dirListPatchesp;
1884 smb_dirListPatch_t *curPatchp;
1887 long orbytes; /* # of bytes in this output record */
1888 long ohbytes; /* # of bytes, except file name */
1889 long onbytes; /* # of bytes in name, incl. term. null */
1890 osi_hyper_t dirLength;
1891 osi_hyper_t bufferOffset;
1892 osi_hyper_t curOffset;
1894 smb_dirSearch_t *dsp;
1898 cm_pageHeader_t *pageHeaderp;
1899 cm_user_t *userp = NULL;
1902 long nextEntryCookie;
1903 int numDirChunks; /* # of 32 byte dir chunks in this entry */
1904 char *op; /* output data ptr */
1905 char *origOp; /* original value of op */
1906 cm_space_t *spacep; /* for pathname buffer */
1907 long maxReturnData; /* max # of return data */
1908 long maxReturnParms; /* max # of return parms */
1909 long bytesInBuffer; /* # data bytes in the output buffer */
1911 char *maskp; /* mask part of path */
1915 smb_tran2Packet_t *outp; /* response packet */
1918 char shortName[13]; /* 8.3 name if needed */
1929 if (p->opcode == 1) {
1930 /* find first; obtain basic parameters from request */
1931 attribute = p->parmsp[0];
1932 maxCount = p->parmsp[1];
1933 infoLevel = p->parmsp[3];
1934 searchFlags = p->parmsp[2];
1935 dsp = smb_NewDirSearch(1);
1936 dsp->attribute = attribute;
1937 pathp = ((char *) p->parmsp) + 12; /* points to path */
1939 maskp = strrchr(pathp, '\\');
1940 if (maskp == NULL) maskp = pathp;
1941 else maskp++; /* skip over backslash */
1942 strcpy(dsp->mask, maskp); /* and save mask */
1943 /* track if this is likely to match a lot of entries */
1944 starPattern = smb_V3IsStarMask(maskp);
1947 osi_assert(p->opcode == 2);
1948 /* find next; obtain basic parameters from request or open dir file */
1949 dsp = smb_FindDirSearch(p->parmsp[0]);
1950 if (!dsp) return CM_ERROR_BADFD;
1951 attribute = dsp->attribute;
1952 maxCount = p->parmsp[1];
1953 infoLevel = p->parmsp[2];
1954 searchFlags = p->parmsp[5];
1956 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
1958 starPattern = 1; /* assume, since required a Find Next */
1962 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
1963 attribute, infoLevel, maxCount, searchFlags);
1965 osi_Log2(afsd_logp, "...T2 search op %d, nextCookie 0x%x",
1966 p->opcode, nextCookie);
1968 if (infoLevel >= 0x101)
1969 searchFlags &= ~4; /* no resume keys */
1971 dirListPatchesp = NULL;
1973 maxReturnData = p->maxReturnData;
1974 if (p->opcode == 1) /* find first */
1975 maxReturnParms = 10; /* bytes */
1977 maxReturnParms = 8; /* bytes */
1979 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
1980 if (maxReturnData > 6000) maxReturnData = 6000;
1981 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
1983 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
1986 osi_Log1(afsd_logp, "T2 receive search dir %s",
1987 osi_LogSaveString(afsd_logp, pathp));
1989 /* bail out if request looks bad */
1990 if (p->opcode == 1 && !pathp) {
1991 smb_ReleaseDirSearch(dsp);
1992 smb_FreeTran2Packet(outp);
1993 return CM_ERROR_BADSMB;
1996 osi_Log2(afsd_logp, "T2 dir search cookie 0x%x, connection %d",
1997 nextCookie, dsp->cookie);
1999 userp = smb_GetTran2User(vcp, p);
2001 osi_Log1(afsd_logp, "T2 dir search unable to resolve user [%d]", p->uid);
2002 smb_ReleaseDirSearch(dsp);
2003 smb_FreeTran2Packet(outp);
2004 return CM_ERROR_BADSMB;
2007 /* try to get the vnode for the path name next */
2008 lock_ObtainMutex(&dsp->mx);
2015 spacep = cm_GetSpace();
2016 smb_StripLastComponent(spacep->data, NULL, pathp);
2017 lock_ReleaseMutex(&dsp->mx);
2019 tidPathp = smb_GetTIDPath(vcp, p->tid);
2020 code = cm_NameI(cm_rootSCachep, spacep->data,
2021 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2022 userp, tidPathp, &req, &scp);
2023 cm_FreeSpace(spacep);
2025 lock_ObtainMutex(&dsp->mx);
2027 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2029 /* we need one hold for the entry we just stored into,
2030 * and one for our own processing. When we're done
2031 * with this function, we'll drop the one for our own
2032 * processing. We held it once from the namei call,
2033 * and so we do another hold now.
2036 lock_ObtainMutex(&scp->mx);
2037 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2038 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2039 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2040 dsp->flags |= SMB_DIRSEARCH_BULKST;
2042 lock_ReleaseMutex(&scp->mx);
2045 lock_ReleaseMutex(&dsp->mx);
2047 cm_ReleaseUser(userp);
2048 smb_FreeTran2Packet(outp);
2049 smb_DeleteDirSearch(dsp);
2050 smb_ReleaseDirSearch(dsp);
2054 /* get the directory size */
2055 lock_ObtainMutex(&scp->mx);
2056 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2057 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2059 lock_ReleaseMutex(&scp->mx);
2060 cm_ReleaseSCache(scp);
2061 cm_ReleaseUser(userp);
2062 smb_FreeTran2Packet(outp);
2063 smb_DeleteDirSearch(dsp);
2064 smb_ReleaseDirSearch(dsp);
2068 dirLength = scp->length;
2070 bufferOffset.LowPart = bufferOffset.HighPart = 0;
2071 curOffset.HighPart = 0;
2072 curOffset.LowPart = nextCookie;
2073 origOp = outp->datap;
2080 if (searchFlags & 4)
2081 /* skip over resume key */
2084 /* make sure that curOffset.LowPart doesn't point to the first
2085 * 32 bytes in the 2nd through last dir page, and that it doesn't
2086 * point at the first 13 32-byte chunks in the first dir page,
2087 * since those are dir and page headers, and don't contain useful
2090 temp = curOffset.LowPart & (2048-1);
2091 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2092 /* we're in the first page */
2093 if (temp < 13*32) temp = 13*32;
2096 /* we're in a later dir page */
2097 if (temp < 32) temp = 32;
2100 /* make sure the low order 5 bits are zero */
2103 /* now put temp bits back ito curOffset.LowPart */
2104 curOffset.LowPart &= ~(2048-1);
2105 curOffset.LowPart |= temp;
2107 /* check if we've passed the dir's EOF */
2108 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2113 /* check if we've returned all the names that will fit in the
2114 * response packet; we check return count as well as the number
2115 * of bytes requested. We check the # of bytes after we find
2116 * the dir entry, since we'll need to check its size.
2118 if (returnedNames >= maxCount) {
2122 /* see if we can use the bufferp we have now; compute in which
2123 * page the current offset would be, and check whether that's
2124 * the offset of the buffer we have. If not, get the buffer.
2126 thyper.HighPart = curOffset.HighPart;
2127 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2128 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2131 buf_Release(bufferp);
2134 lock_ReleaseMutex(&scp->mx);
2135 lock_ObtainRead(&scp->bufCreateLock);
2136 code = buf_Get(scp, &thyper, &bufferp);
2137 lock_ReleaseRead(&scp->bufCreateLock);
2139 /* now, if we're doing a star match, do bulk fetching
2140 * of all of the status info for files in the dir.
2143 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2146 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2147 && LargeIntegerGreaterThanOrEqualTo(
2148 thyper, scp->bulkStatProgress)) {
2149 /* Don't bulk stat if risking timeout */
2150 int now = GetCurrentTime();
2151 if (now - req.startTime > 5000) {
2152 scp->bulkStatProgress = thyper;
2153 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2154 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2156 cm_TryBulkStat(scp, &thyper,
2161 lock_ObtainMutex(&scp->mx);
2163 bufferOffset = thyper;
2165 /* now get the data in the cache */
2167 code = cm_SyncOp(scp, bufferp, userp, &req,
2169 CM_SCACHESYNC_NEEDCALLBACK
2170 | CM_SCACHESYNC_READ);
2173 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2175 /* otherwise, load the buffer and try again */
2176 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2181 buf_Release(bufferp);
2185 } /* if (wrong buffer) ... */
2187 /* now we have the buffer containing the entry we're interested
2188 * in; copy it out if it represents a non-deleted entry.
2190 entryInDir = curOffset.LowPart & (2048-1);
2191 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2193 /* page header will help tell us which entries are free. Page
2194 * header can change more often than once per buffer, since
2195 * AFS 3 dir page size may be less than (but not more than)
2196 * a buffer package buffer.
2198 /* only look intra-buffer */
2199 temp = curOffset.LowPart & (buf_bufferSize - 1);
2200 temp &= ~(2048 - 1); /* turn off intra-page bits */
2201 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2203 /* now determine which entry we're looking at in the page.
2204 * If it is free (there's a free bitmap at the start of the
2205 * dir), we should skip these 32 bytes.
2207 slotInPage = (entryInDir & 0x7e0) >> 5;
2208 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2209 & (1 << (slotInPage & 0x7)))) {
2210 /* this entry is free */
2211 numDirChunks = 1; /* only skip this guy */
2215 tp = bufferp->datap + entryInBuffer;
2216 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
2218 /* while we're here, compute the next entry's location, too,
2219 * since we'll need it when writing out the cookie into the dir
2222 * XXXX Probably should do more sanity checking.
2224 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2226 /* compute offset of cookie representing next entry */
2227 nextEntryCookie = curOffset.LowPart
2228 + (CM_DIR_CHUNKSIZE * numDirChunks);
2230 /* Need 8.3 name? */
2232 if (infoLevel == 0x104
2233 && dep->fid.vnode != 0
2234 && !cm_Is8Dot3(dep->name)) {
2235 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2239 if (dep->fid.vnode != 0
2240 && (smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)
2242 && smb_V3MatchMask(shortName, maskp,
2243 CM_FLAG_CASEFOLD)))) {
2245 /* Eliminate entries that don't match requested
2247 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
2248 smb_IsDotFile(dep->name))
2249 goto nextEntry; /* no hidden files */
2251 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
2253 /* We have already done the cm_TryBulkStat above */
2254 fid.cell = scp->fid.cell;
2255 fid.volume = scp->fid.volume;
2256 fid.vnode = ntohl(dep->fid.vnode);
2257 fid.unique = ntohl(dep->fid.unique);
2258 fileType = cm_FindFileType(&fid);
2259 /*osi_Log2(afsd_logp, "smb_ReceiveTran2SearchDir: file %s "
2260 "has filetype %d", dep->name,
2262 if (fileType == CM_SCACHETYPE_DIRECTORY)
2266 /* finally check if this name will fit */
2268 /* standard dir entry stuff */
2269 if (infoLevel < 0x101)
2270 ohbytes = 23; /* pre-NT */
2271 else if (infoLevel == 0x103)
2272 ohbytes = 12; /* NT names only */
2274 ohbytes = 64; /* NT */
2276 if (infoLevel == 0x104)
2277 ohbytes += 26; /* Short name & length */
2279 if (searchFlags & 4) {
2280 ohbytes += 4; /* if resume key required */
2284 && infoLevel != 0x101
2285 && infoLevel != 0x103)
2286 ohbytes += 4; /* EASIZE */
2288 /* add header to name & term. null */
2289 orbytes = onbytes + ohbytes + 1;
2291 /* now, we round up the record to a 4 byte alignment,
2292 * and we make sure that we have enough room here for
2293 * even the aligned version (so we don't have to worry
2294 * about an * overflow when we pad things out below).
2295 * That's the reason for the alignment arithmetic below.
2297 if (infoLevel >= 0x101)
2298 align = (4 - (orbytes & 3)) & 3;
2301 if (orbytes + bytesInBuffer + align > maxReturnData)
2304 /* this is one of the entries to use: it is not deleted
2305 * and it matches the star pattern we're looking for.
2306 * Put out the name, preceded by its length.
2308 /* First zero everything else */
2309 memset(origOp, 0, ohbytes);
2311 if (infoLevel <= 0x101)
2312 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2313 else if (infoLevel == 0x103)
2314 *((u_long *)(op + 8)) = onbytes;
2316 *((u_long *)(op + 60)) = onbytes;
2317 strcpy(origOp+ohbytes, dep->name);
2319 /* Short name if requested and needed */
2320 if (infoLevel == 0x104) {
2321 if (NeedShortName) {
2322 strcpy(op + 70, shortName);
2323 *(op + 68) = shortNameEnd - shortName;
2327 /* now, adjust the # of entries copied */
2330 /* NextEntryOffset and FileIndex */
2331 if (infoLevel >= 101) {
2332 int entryOffset = orbytes + align;
2333 *((u_long *)op) = entryOffset;
2334 *((u_long *)(op+4)) = nextEntryCookie;
2337 /* now we emit the attribute. This is tricky, since
2338 * we need to really stat the file to find out what
2339 * type of entry we've got. Right now, we're copying
2340 * out data from * a buffer, while holding the scp
2341 * locked, so it isn't really convenient to stat
2342 * something now. We'll put in a place holder
2343 * now, and make a second pass before returning this
2344 * to get the real attributes. So, we just skip the
2345 * data for now, and adjust it later. We allocate a
2346 * patch record to make it easy to find this point
2347 * later. The replay will happen at a time when it is
2348 * safe to unlock the directory.
2350 if (infoLevel != 0x103) {
2351 curPatchp = malloc(sizeof(*curPatchp));
2352 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2354 curPatchp->dptr = op;
2355 if (infoLevel >= 0x101)
2356 curPatchp->dptr += 8;
2358 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
2359 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
2362 curPatchp->flags = 0;
2364 curPatchp->fid.cell = scp->fid.cell;
2365 curPatchp->fid.volume = scp->fid.volume;
2366 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2367 curPatchp->fid.unique = ntohl(dep->fid.unique);
2370 curPatchp->dep = dep;
2373 if (searchFlags & 4)
2374 /* put out resume key */
2375 *((u_long *)origOp) = nextEntryCookie;
2377 /* Adjust byte ptr and count */
2378 origOp += orbytes; /* skip entire record */
2379 bytesInBuffer += orbytes;
2381 /* and pad the record out */
2382 while (--align >= 0) {
2387 } /* if we're including this name */
2390 /* and adjust curOffset to be where the new cookie is */
2391 thyper.HighPart = 0;
2392 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2393 curOffset = LargeIntegerAdd(thyper, curOffset);
2394 } /* while copying data for dir listing */
2396 /* release the mutex */
2397 lock_ReleaseMutex(&scp->mx);
2398 if (bufferp) buf_Release(bufferp);
2400 /* apply and free last set of patches; if not doing a star match, this
2401 * will be empty, but better safe (and freeing everything) than sorry.
2403 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2406 /* now put out the final parameters */
2407 if (returnedNames == 0) eos = 1;
2408 if (p->opcode == 1) {
2410 outp->parmsp[0] = (unsigned short) dsp->cookie;
2411 outp->parmsp[1] = returnedNames;
2412 outp->parmsp[2] = eos;
2413 outp->parmsp[3] = 0; /* nothing wrong with EAS */
2414 outp->parmsp[4] = 0; /* don't need last name to continue
2415 * search, cookie is enough. Normally,
2416 * this is the offset of the file name
2417 * of the last entry returned.
2419 outp->totalParms = 10; /* in bytes */
2423 outp->parmsp[0] = returnedNames;
2424 outp->parmsp[1] = eos;
2425 outp->parmsp[2] = 0; /* EAS error */
2426 outp->parmsp[3] = 0; /* last name, as above */
2427 outp->totalParms = 8; /* in bytes */
2430 /* return # of bytes in the buffer */
2431 outp->totalData = bytesInBuffer;
2433 osi_Log2(afsd_logp, "T2 search dir done, %d names, code %d",
2434 returnedNames, code);
2436 /* Return error code if unsuccessful on first request */
2437 if (code == 0 && p->opcode == 1 && returnedNames == 0)
2438 code = CM_ERROR_NOSUCHFILE;
2440 /* if we're supposed to close the search after this request, or if
2441 * we're supposed to close the search if we're done, and we're done,
2442 * or if something went wrong, close the search.
2444 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2445 if ((searchFlags & 1) || (returnedNames == 0) || ((searchFlags & 2) &&
2447 smb_DeleteDirSearch(dsp);
2449 smb_SendTran2Error(vcp, p, opx, code);
2451 smb_SendTran2Packet(vcp, outp, opx);
2453 smb_FreeTran2Packet(outp);
2454 smb_ReleaseDirSearch(dsp);
2455 cm_ReleaseSCache(scp);
2456 cm_ReleaseUser(userp);
2460 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2463 smb_dirSearch_t *dsp;
2465 dirHandle = smb_GetSMBParm(inp, 0);
2467 osi_Log1(afsd_logp, "SMB3 find close handle %d", dirHandle);
2469 dsp = smb_FindDirSearch(dirHandle);
2472 return CM_ERROR_BADFD;
2474 /* otherwise, we have an FD to destroy */
2475 smb_DeleteDirSearch(dsp);
2476 smb_ReleaseDirSearch(dsp);
2478 /* and return results */
2479 smb_SetSMBDataLength(outp, 0);
2484 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2486 smb_SetSMBDataLength(outp, 0);
2490 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2497 cm_scache_t *dscp; /* dir we're dealing with */
2498 cm_scache_t *scp; /* file we're creating */
2500 int initialModeBits;
2510 int parmSlot; /* which parm we're dealing with */
2518 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
2519 openFun = smb_GetSMBParm(inp, 8); /* open function */
2520 excl = ((openFun & 3) == 0);
2521 trunc = ((openFun & 3) == 2); /* truncate it */
2522 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2523 openAction = 0; /* tracks what we did */
2525 attributes = smb_GetSMBParm(inp, 5);
2526 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2528 /* compute initial mode bits based on read-only flag in attributes */
2529 initialModeBits = 0666;
2530 if (attributes & 1) initialModeBits &= ~0222;
2532 pathp = smb_GetSMBData(inp, NULL);
2534 spacep = inp->spacep;
2535 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2537 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2538 /* special case magic file name for receiving IOCTL requests
2539 * (since IOCTL calls themselves aren't getting through).
2542 osi_Log0(afsd_logp, "IOCTL Open");
2545 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2546 smb_SetupIoctlFid(fidp, spacep);
2548 /* set inp->fid so that later read calls in same msg can find fid */
2549 inp->fid = fidp->fid;
2551 /* copy out remainder of the parms */
2553 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2555 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2556 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
2557 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2558 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
2559 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2560 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2561 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2562 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2564 /* and the final "always present" stuff */
2565 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2566 /* next write out the "unique" ID */
2567 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2568 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2569 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2570 smb_SetSMBDataLength(outp, 0);
2572 /* and clean up fid reference */
2573 smb_ReleaseFID(fidp);
2577 #ifdef DEBUG_VERBOSE
2579 char *hexp, *asciip;
2580 asciip = (lastNamep ? lastNamep : pathp );
2581 hexp = osi_HexifyString(asciip);
2582 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
2586 userp = smb_GetUser(vcp, inp);
2589 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2590 code = cm_NameI(cm_rootSCachep, pathp,
2591 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2592 userp, tidPathp, &req, &scp);
2594 code = cm_NameI(cm_rootSCachep, spacep->data,
2595 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2596 userp, tidPathp, &req, &dscp);
2599 cm_ReleaseUser(userp);
2603 /* otherwise, scp points to the parent directory. Do a lookup,
2604 * and truncate the file if we find it, otherwise we create the
2607 if (!lastNamep) lastNamep = pathp;
2609 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2611 if (code && code != CM_ERROR_NOSUCHFILE) {
2612 cm_ReleaseSCache(dscp);
2613 cm_ReleaseUser(userp);
2618 /* if we get here, if code is 0, the file exists and is represented by
2619 * scp. Otherwise, we have to create it. The dir may be represented
2620 * by dscp, or we may have found the file directly. If code is non-zero,
2624 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2626 if (dscp) cm_ReleaseSCache(dscp);
2627 cm_ReleaseSCache(scp);
2628 cm_ReleaseUser(userp);
2633 /* oops, file shouldn't be there */
2634 if (dscp) cm_ReleaseSCache(dscp);
2635 cm_ReleaseSCache(scp);
2636 cm_ReleaseUser(userp);
2637 return CM_ERROR_EXISTS;
2641 setAttr.mask = CM_ATTRMASK_LENGTH;
2642 setAttr.length.LowPart = 0;
2643 setAttr.length.HighPart = 0;
2644 code = cm_SetAttr(scp, &setAttr, userp, &req);
2645 openAction = 3; /* truncated existing file */
2647 else openAction = 1; /* found existing file */
2649 else if (!(openFun & 0x10)) {
2650 /* don't create if not found */
2651 if (dscp) cm_ReleaseSCache(dscp);
2652 cm_ReleaseUser(userp);
2653 return CM_ERROR_NOSUCHFILE;
2656 osi_assert(dscp != NULL);
2657 osi_Log1(afsd_logp, "smb_ReceiveV3OpenX creating file %s",
2658 osi_LogSaveString(afsd_logp, lastNamep));
2659 openAction = 2; /* created file */
2660 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2661 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2662 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2664 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2665 smb_NotifyChange(FILE_ACTION_ADDED,
2666 FILE_NOTIFY_CHANGE_FILE_NAME,
2667 dscp, lastNamep, NULL, TRUE);
2668 if (!excl && code == CM_ERROR_EXISTS) {
2669 /* not an exclusive create, and someone else tried
2670 * creating it already, then we open it anyway. We
2671 * don't bother retrying after this, since if this next
2672 * fails, that means that the file was deleted after we
2673 * started this call.
2675 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2679 setAttr.mask = CM_ATTRMASK_LENGTH;
2680 setAttr.length.LowPart = 0;
2681 setAttr.length.HighPart = 0;
2682 code = cm_SetAttr(scp, &setAttr, userp, &req);
2684 } /* lookup succeeded */
2688 /* we don't need this any longer */
2689 if (dscp) cm_ReleaseSCache(dscp);
2692 /* something went wrong creating or truncating the file */
2693 if (scp) cm_ReleaseSCache(scp);
2694 cm_ReleaseUser(userp);
2698 /* make sure we're about to open a file */
2699 if (scp->fileType != CM_SCACHETYPE_FILE) {
2700 cm_ReleaseSCache(scp);
2701 cm_ReleaseUser(userp);
2702 return CM_ERROR_ISDIR;
2705 /* now all we have to do is open the file itself */
2706 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2709 /* save a pointer to the vnode */
2712 /* compute open mode */
2713 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2714 if (openMode == 1 || openMode == 2)
2715 fidp->flags |= SMB_FID_OPENWRITE;
2717 smb_ReleaseFID(fidp);
2719 cm_Open(scp, 0, userp);
2721 /* set inp->fid so that later read calls in same msg can find fid */
2722 inp->fid = fidp->fid;
2724 /* copy out remainder of the parms */
2726 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2727 lock_ObtainMutex(&scp->mx);
2729 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2730 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2731 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2732 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2733 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2734 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2735 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2736 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2737 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2739 /* and the final "always present" stuff */
2740 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2741 /* next write out the "unique" ID */
2742 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2743 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2744 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2745 lock_ReleaseMutex(&scp->mx);
2746 smb_SetSMBDataLength(outp, 0);
2748 osi_Log1(afsd_logp, "SMB OpenX opening fid %d", fidp->fid);
2750 cm_ReleaseUser(userp);
2751 /* leave scp held since we put it in fidp->scp */
2755 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2762 unsigned char LockType;
2763 unsigned short NumberOfUnlocks, NumberOfLocks;
2764 unsigned long Timeout;
2766 LARGE_INTEGER LOffset, LLength;
2767 smb_waitingLock_t *waitingLock;
2774 fid = smb_GetSMBParm(inp, 2);
2775 fid = smb_ChainFID(fid, inp);
2777 fidp = smb_FindFID(vcp, fid, 0);
2778 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2779 return CM_ERROR_BADFD;
2781 /* set inp->fid so that later read calls in same msg can find fid */
2784 userp = smb_GetUser(vcp, inp);
2788 lock_ObtainMutex(&scp->mx);
2789 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2790 CM_SCACHESYNC_NEEDCALLBACK
2791 | CM_SCACHESYNC_GETSTATUS
2792 | CM_SCACHESYNC_LOCK);
2793 if (code) goto doneSync;
2795 LockType = smb_GetSMBParm(inp, 3) & 0xff;
2796 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2797 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2798 NumberOfLocks = smb_GetSMBParm(inp, 7);
2800 op = smb_GetSMBData(inp, NULL);
2802 for (i=0; i<NumberOfUnlocks; i++) {
2803 if (LockType & 0x10) {
2805 LOffset.HighPart = *((LONG *)(op + 4));
2806 LOffset.LowPart = *((DWORD *)(op + 8));
2807 LLength.HighPart = *((LONG *)(op + 12));
2808 LLength.LowPart = *((DWORD *)(op + 16));
2812 /* Not Large Files */
2813 LOffset.HighPart = 0;
2814 LOffset.LowPart = *((DWORD *)(op + 2));
2815 LLength.HighPart = 0;
2816 LLength.LowPart = *((DWORD *)(op + 6));
2819 if (LargeIntegerNotEqualToZero(LOffset))
2821 /* Do not check length -- length check done in cm_Unlock */
2823 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2824 if (code) goto done;
2827 for (i=0; i<NumberOfLocks; i++) {
2828 if (LockType & 0x10) {
2830 LOffset.HighPart = *((LONG *)(op + 4));
2831 LOffset.LowPart = *((DWORD *)(op + 8));
2832 LLength.HighPart = *((LONG *)(op + 12));
2833 LLength.LowPart = *((DWORD *)(op + 16));
2837 /* Not Large Files */
2838 LOffset.HighPart = 0;
2839 LOffset.LowPart = *((DWORD *)(op + 2));
2840 LLength.HighPart = 0;
2841 LLength.LowPart = *((DWORD *)(op + 6));
2844 if (LargeIntegerNotEqualToZero(LOffset))
2846 if (LargeIntegerLessThan(LOffset, scp->length))
2849 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2850 userp, &req, &lockp);
2851 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2852 /* Put on waiting list */
2853 waitingLock = malloc(sizeof(smb_waitingLock_t));
2854 waitingLock->vcp = vcp;
2855 waitingLock->inp = smb_CopyPacket(inp);
2856 waitingLock->outp = smb_CopyPacket(outp);
2857 waitingLock->timeRemaining = Timeout;
2858 waitingLock->lockp = lockp;
2859 lock_ObtainWrite(&smb_globalLock);
2860 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2862 osi_Wakeup((long) &smb_allWaitingLocks);
2863 lock_ReleaseWrite(&smb_globalLock);
2864 /* don't send reply immediately */
2865 outp->flags |= SMB_PACKETFLAG_NOSEND;
2871 /* release any locks acquired before the failure */
2874 smb_SetSMBDataLength(outp, 0);
2876 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2878 lock_ReleaseMutex(&scp->mx);
2879 cm_ReleaseUser(userp);
2880 smb_ReleaseFID(fidp);
2885 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2897 fid = smb_GetSMBParm(inp, 0);
2898 fid = smb_ChainFID(fid, inp);
2900 fidp = smb_FindFID(vcp, fid, 0);
2901 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2902 return CM_ERROR_BADFD;
2905 userp = smb_GetUser(vcp, inp);
2909 /* otherwise, stat the file */
2910 lock_ObtainMutex(&scp->mx);
2911 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2912 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2913 if (code) goto done;
2915 /* decode times. We need a search time, but the response to this
2916 * call provides the date first, not the time, as returned in the
2917 * searchTime variable. So we take the high-order bits first.
2919 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2920 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
2921 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2922 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
2923 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2924 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
2925 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2927 /* now handle file size and allocation size */
2928 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
2929 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2930 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
2931 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2933 /* file attribute */
2934 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2936 /* and finalize stuff */
2937 smb_SetSMBDataLength(outp, 0);
2941 lock_ReleaseMutex(&scp->mx);
2942 cm_ReleaseUser(userp);
2943 smb_ReleaseFID(fidp);
2947 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2961 fid = smb_GetSMBParm(inp, 0);
2962 fid = smb_ChainFID(fid, inp);
2964 fidp = smb_FindFID(vcp, fid, 0);
2965 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2966 return CM_ERROR_BADFD;
2969 userp = smb_GetUser(vcp, inp);
2973 /* now prepare to call cm_setattr. This message only sets various times,
2974 * and AFS only implements mtime, and we'll set the mtime if that's
2975 * requested. The others we'll ignore.
2977 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
2979 if (searchTime != 0) {
2980 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
2982 if ( unixTime != -1 ) {
2983 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
2984 attrs.clientModTime = unixTime;
2985 code = cm_SetAttr(scp, &attrs, userp, &req);
2987 osi_Log1(afsd_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
2989 osi_Log1(afsd_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
2994 cm_ReleaseUser(userp);
2995 smb_ReleaseFID(fidp);
3000 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3003 long count, finalCount;
3010 fd = smb_GetSMBParm(inp, 2);
3011 count = smb_GetSMBParm(inp, 5);
3012 offset.HighPart = 0; /* too bad */
3013 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
3015 osi_Log3(afsd_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
3016 fd, offset.LowPart, count);
3018 fd = smb_ChainFID(fd, inp);
3019 fidp = smb_FindFID(vcp, fd, 0);
3021 return CM_ERROR_BADFD;
3023 /* set inp->fid so that later read calls in same msg can find fid */
3026 if (fidp->flags & SMB_FID_IOCTL) {
3027 return smb_IoctlV3Read(fidp, vcp, inp, outp);
3030 userp = smb_GetUser(vcp, inp);
3032 /* 0 and 1 are reserved for request chaining, were setup by our caller,
3033 * and will be further filled in after we return.
3035 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
3036 smb_SetSMBParm(outp, 3, 0); /* resvd */
3037 smb_SetSMBParm(outp, 4, 0); /* resvd */
3038 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
3039 /* fill in #6 when we have all the parameters' space reserved */
3040 smb_SetSMBParm(outp, 7, 0); /* resv'd */
3041 smb_SetSMBParm(outp, 8, 0); /* resv'd */
3042 smb_SetSMBParm(outp, 9, 0); /* resv'd */
3043 smb_SetSMBParm(outp, 10, 0); /* resv'd */
3044 smb_SetSMBParm(outp, 11, 0); /* reserved */
3046 /* get op ptr after putting in the parms, since otherwise we don't
3047 * know where the data really is.
3049 op = smb_GetSMBData(outp, NULL);
3051 /* now fill in offset from start of SMB header to first data byte (to op) */
3052 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
3054 /* set the packet data length the count of the # of bytes */
3055 smb_SetSMBDataLength(outp, count);
3058 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
3060 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
3063 /* fix some things up */
3064 smb_SetSMBParm(outp, 5, finalCount);
3065 smb_SetSMBDataLength(outp, finalCount);
3067 smb_ReleaseFID(fidp);
3069 cm_ReleaseUser(userp);
3074 * Values for createDisp, copied from NTDDK.H
3076 * FILE_SUPERSEDE 0 (???)
3077 * FILE_OPEN 1 (open)
3078 * FILE_CREATE 2 (exclusive)
3079 * FILE_OPEN_IF 3 (non-exclusive)
3080 * FILE_OVERWRITE 4 (open & truncate, but do not create)
3081 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
3084 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3086 char *pathp, *realPathp;
3090 cm_scache_t *dscp; /* parent dir */
3091 cm_scache_t *scp; /* file to create or open */
3095 unsigned short nameLength;
3097 unsigned int requestOpLock;
3098 unsigned int requestBatchOpLock;
3099 unsigned int mustBeDir;
3100 unsigned int treeCreate;
3102 unsigned int desiredAccess;
3103 unsigned int extAttributes;
3104 unsigned int createDisp;
3105 unsigned int createOptions;
3106 int initialModeBits;
3107 unsigned short baseFid;
3108 smb_fid_t *baseFidp;
3110 cm_scache_t *baseDirp;
3111 unsigned short openAction;
3126 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3127 flags = smb_GetSMBOffsetParm(inp, 3, 1)
3128 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3129 requestOpLock = flags & 0x02;
3130 requestBatchOpLock = flags & 0x04;
3131 mustBeDir = flags & 0x08;
3134 * Why all of a sudden 32-bit FID?
3135 * We will reject all bits higher than 16.
3137 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3138 return CM_ERROR_INVAL;
3139 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3140 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3141 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3142 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3143 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3144 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3145 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3146 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3147 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3149 /* mustBeDir is never set; createOptions directory bit seems to be
3152 if (createOptions & 1)
3154 else if (createOptions & 0x40)
3160 * compute initial mode bits based on read-only flag in
3161 * extended attributes
3163 initialModeBits = 0666;
3164 if (extAttributes & 1) initialModeBits &= ~0222;
3166 pathp = smb_GetSMBData(inp, NULL);
3167 /* Sometimes path is not null-terminated, so we make a copy. */
3168 realPathp = malloc(nameLength+1);
3169 memcpy(realPathp, pathp, nameLength);
3170 realPathp[nameLength] = 0;
3172 spacep = inp->spacep;
3173 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3175 osi_Log1(afsd_logp,"NTCreateX for [%s]",osi_LogSaveString(afsd_logp,realPathp));
3176 osi_Log4(afsd_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
3178 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3179 /* special case magic file name for receiving IOCTL requests
3180 * (since IOCTL calls themselves aren't getting through).
3182 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3183 smb_SetupIoctlFid(fidp, spacep);
3185 /* set inp->fid so that later read calls in same msg can find fid */
3186 inp->fid = fidp->fid;
3190 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3191 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3192 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3194 memset(&ft, 0, sizeof(ft));
3195 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3196 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3197 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3198 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3199 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3200 sz.HighPart = 0x7fff; sz.LowPart = 0;
3201 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3202 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3203 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3204 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3205 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
3206 smb_SetSMBDataLength(outp, 0);
3208 /* clean up fid reference */
3209 smb_ReleaseFID(fidp);
3214 #ifdef DEBUG_VERBOSE
3216 char *hexp, *asciip;
3217 asciip = (lastNamep? lastNamep : realPathp);
3218 hexp = osi_HexifyString( asciip );
3219 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
3223 userp = smb_GetUser(vcp, inp);
3225 osi_Log1(afsd_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
3227 return CM_ERROR_INVAL;
3231 baseDirp = cm_rootSCachep;
3232 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3235 baseFidp = smb_FindFID(vcp, baseFid, 0);
3237 osi_Log1(afsd_logp, "NTCreateX Invalid base fid [%d]", baseFid);
3239 cm_ReleaseUser(userp);
3240 return CM_ERROR_INVAL;
3242 baseDirp = baseFidp->scp;
3246 osi_Log1(afsd_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(afsd_logp,tidPathp));
3248 /* compute open mode */
3250 if (desiredAccess & DELETE)
3251 fidflags |= SMB_FID_OPENDELETE;
3252 if (desiredAccess & AFS_ACCESS_READ)
3253 fidflags |= SMB_FID_OPENREAD;
3254 if (desiredAccess & AFS_ACCESS_WRITE)
3255 fidflags |= SMB_FID_OPENWRITE;
3259 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3260 userp, tidPathp, &req, &scp);
3261 if (code == 0) foundscp = TRUE;
3263 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3264 /* look up parent directory */
3265 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
3266 the immediate parent. We have to work our way up realPathp until we hit something that we
3273 code = cm_NameI(baseDirp, spacep->data,
3274 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3275 userp, tidPathp, &req, &dscp);
3278 (tp = strrchr(spacep->data,'\\')) &&
3279 (createDisp == 2) &&
3280 (realDirFlag == 1)) {
3283 treeStartp = realPathp + (tp - spacep->data);
3285 if (*tp && !smb_IsLegalFilename(tp)) {
3286 if(baseFid != 0) smb_ReleaseFID(baseFidp);
3287 cm_ReleaseUser(userp);
3289 return CM_ERROR_BADNTFILENAME;
3296 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3299 osi_Log0(afsd_logp,"NTCreateX parent not found");
3300 cm_ReleaseUser(userp);
3305 if(treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
3306 /* A file exists where we want a directory. */
3307 cm_ReleaseSCache(dscp);
3308 cm_ReleaseUser(userp);
3310 return CM_ERROR_EXISTS;
3313 if (!lastNamep) lastNamep = realPathp;
3316 if (!smb_IsLegalFilename(lastNamep)) {
3317 cm_ReleaseSCache(dscp);
3318 cm_ReleaseUser(userp);
3320 return CM_ERROR_BADNTFILENAME;
3323 if (!foundscp && !treeCreate) {
3324 code = cm_Lookup(dscp, lastNamep,
3325 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3327 if (code && code != CM_ERROR_NOSUCHFILE) {
3328 cm_ReleaseSCache(dscp);
3329 cm_ReleaseUser(userp);
3336 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3339 /* if we get here, if code is 0, the file exists and is represented by
3340 * scp. Otherwise, we have to create it. The dir may be represented
3341 * by dscp, or we may have found the file directly. If code is non-zero,
3344 if (code == 0 && !treeCreate) {
3345 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3348 if (dscp) cm_ReleaseSCache(dscp);
3349 cm_ReleaseSCache(scp);
3350 cm_ReleaseUser(userp);
3355 if (createDisp == 2) {
3356 /* oops, file shouldn't be there */
3357 if (dscp) cm_ReleaseSCache(dscp);
3358 cm_ReleaseSCache(scp);
3359 cm_ReleaseUser(userp);
3361 return CM_ERROR_EXISTS;
3365 || createDisp == 5) {
3366 setAttr.mask = CM_ATTRMASK_LENGTH;
3367 setAttr.length.LowPart = 0;
3368 setAttr.length.HighPart = 0;
3369 code = cm_SetAttr(scp, &setAttr, userp, &req);
3370 openAction = 3; /* truncated existing file */
3372 else openAction = 1; /* found existing file */
3374 else if (createDisp == 1 || createDisp == 4) {
3375 /* don't create if not found */
3376 if (dscp) cm_ReleaseSCache(dscp);
3377 cm_ReleaseUser(userp);
3379 return CM_ERROR_NOSUCHFILE;
3381 else if (realDirFlag == 0 || realDirFlag == -1) {
3382 osi_assert(dscp != NULL);
3383 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating file %s",
3384 osi_LogSaveString(afsd_logp, lastNamep));
3385 openAction = 2; /* created file */
3386 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3387 setAttr.clientModTime = time(NULL);
3388 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3390 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3391 smb_NotifyChange(FILE_ACTION_ADDED,
3392 FILE_NOTIFY_CHANGE_FILE_NAME,
3393 dscp, lastNamep, NULL, TRUE);
3394 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3395 /* Not an exclusive create, and someone else tried
3396 * creating it already, then we open it anyway. We
3397 * don't bother retrying after this, since if this next
3398 * fails, that means that the file was deleted after we
3399 * started this call.
3401 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3404 if (createDisp == 5) {
3405 setAttr.mask = CM_ATTRMASK_LENGTH;
3406 setAttr.length.LowPart = 0;
3407 setAttr.length.HighPart = 0;
3408 code = cm_SetAttr(scp, &setAttr, userp,
3411 } /* lookup succeeded */
3416 char *cp; /* This component */
3417 int clen = 0; /* length of component */
3421 /* create directory */
3422 if ( !treeCreate ) treeStartp = lastNamep;
3423 osi_assert(dscp != NULL);
3424 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating directory [%s]",
3425 osi_LogSaveString(afsd_logp, treeStartp));
3426 openAction = 2; /* created directory */
3428 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3429 setAttr.clientModTime = time(NULL);
3436 tp = strchr(pp, '\\');
3440 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
3444 strncpy(cp,pp,clen);
3450 if(clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
3452 /* cp is the next component to be created. */
3453 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
3454 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
3455 smb_NotifyChange(FILE_ACTION_ADDED,
3456 FILE_NOTIFY_CHANGE_DIR_NAME,
3457 tscp, cp, NULL, TRUE);
3459 (code == CM_ERROR_EXISTS && createDisp != 2)) {
3460 /* Not an exclusive create, and someone else tried
3461 * creating it already, then we open it anyway. We
3462 * don't bother retrying after this, since if this next
3463 * fails, that means that the file was deleted after we
3464 * started this call.
3466 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
3471 if(!isLast) { /* for anything other than dscp, release it unless it's the last one */
3472 cm_ReleaseSCache(tscp);
3473 tscp = scp; /* Newly created directory will be next parent */
3478 if we get here and code == 0, then scp is the last directory created, and tscp is the
3479 parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
3485 /* something went wrong creating or truncating the file */
3486 if (scp) cm_ReleaseSCache(scp);
3487 if (dscp) cm_ReleaseSCache(dscp);
3488 cm_ReleaseUser(userp);
3493 /* make sure we have file vs. dir right (only applies for single component case) */
3494 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3495 cm_ReleaseSCache(scp);
3496 if (dscp) cm_ReleaseSCache(dscp);
3497 cm_ReleaseUser(userp);
3499 return CM_ERROR_ISDIR;
3501 /* (only applies to single component case) */
3502 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3503 cm_ReleaseSCache(scp);
3504 if (dscp) cm_ReleaseSCache(dscp);
3505 cm_ReleaseUser(userp);
3507 return CM_ERROR_NOTDIR;
3510 /* open the file itself */
3511 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3513 /* save a pointer to the vnode */
3516 fidp->flags = fidflags;
3518 /* save parent dir and pathname for delete or change notification */
3519 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3520 fidp->flags |= SMB_FID_NTOPEN;
3521 fidp->NTopen_dscp = dscp;
3522 cm_HoldSCache(dscp);
3523 fidp->NTopen_pathp = strdup(lastNamep);
3525 fidp->NTopen_wholepathp = realPathp;
3527 /* we don't need this any longer */
3528 if (dscp) cm_ReleaseSCache(dscp);
3529 cm_Open(scp, 0, userp);
3531 /* set inp->fid so that later read calls in same msg can find fid */
3532 inp->fid = fidp->fid;
3536 lock_ObtainMutex(&scp->mx);
3537 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3538 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3539 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3540 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3541 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3542 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3543 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3544 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3545 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3547 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3548 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3549 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3550 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3551 smb_SetSMBParmByte(outp, parmSlot,
3552 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3553 lock_ReleaseMutex(&scp->mx);
3554 smb_SetSMBDataLength(outp, 0);
3556 osi_Log2(afsd_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3557 osi_LogSaveString(afsd_logp, realPathp));
3559 smb_ReleaseFID(fidp);
3561 cm_ReleaseUser(userp);
3563 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
3565 /* leave scp held since we put it in fidp->scp */
3570 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3571 * Instead, ultimately, would like to use a subroutine for common code.
3573 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3575 char *pathp, *realPathp;
3579 cm_scache_t *dscp; /* parent dir */
3580 cm_scache_t *scp; /* file to create or open */
3583 unsigned long nameLength;
3585 unsigned int requestOpLock;
3586 unsigned int requestBatchOpLock;
3587 unsigned int mustBeDir;
3588 unsigned int extendedRespRequired;
3590 unsigned int desiredAccess;
3591 #ifdef DEBUG_VERBOSE
3592 unsigned int allocSize;
3593 unsigned int shareAccess;
3595 unsigned int extAttributes;
3596 unsigned int createDisp;
3597 #ifdef DEBUG_VERBOSE
3600 unsigned int createOptions;
3601 int initialModeBits;
3602 unsigned short baseFid;
3603 smb_fid_t *baseFidp;
3605 cm_scache_t *baseDirp;
3606 unsigned short openAction;
3612 int parmOffset, dataOffset;
3623 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3624 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3625 parmp = inp->data + parmOffset;
3626 lparmp = (ULONG *) parmp;
3629 requestOpLock = flags & 0x02;
3630 requestBatchOpLock = flags & 0x04;
3631 mustBeDir = flags & 0x08;
3632 extendedRespRequired = flags & 0x10;
3635 * Why all of a sudden 32-bit FID?
3636 * We will reject all bits higher than 16.
3638 if (lparmp[1] & 0xFFFF0000)
3639 return CM_ERROR_INVAL;
3640 baseFid = (unsigned short)lparmp[1];
3641 desiredAccess = lparmp[2];
3642 #ifdef DEBUG_VERBOSE
3643 allocSize = lparmp[3];
3644 #endif /* DEBUG_VERSOSE */
3645 extAttributes = lparmp[5];
3647 shareAccess = lparmp[6];
3649 createDisp = lparmp[7];
3650 createOptions = lparmp[8];
3651 #ifdef DEBUG_VERBOSE
3654 nameLength = lparmp[11];
3656 #ifdef DEBUG_VERBOSE
3657 osi_Log4(afsd_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
3658 osi_Log2(afsd_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
3659 osi_Log1(afsd_logp,"... flags[%x]",flags);
3662 /* mustBeDir is never set; createOptions directory bit seems to be
3665 if (createOptions & 1)
3667 else if (createOptions & 0x40)
3673 * compute initial mode bits based on read-only flag in
3674 * extended attributes
3676 initialModeBits = 0666;
3677 if (extAttributes & 1) initialModeBits &= ~0222;
3679 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3680 /* Sometimes path is not null-terminated, so we make a copy. */
3681 realPathp = malloc(nameLength+1);
3682 memcpy(realPathp, pathp, nameLength);
3683 realPathp[nameLength] = 0;
3685 spacep = cm_GetSpace();
3686 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3689 * Nothing here to handle SMB_IOCTL_FILENAME.
3690 * Will add it if necessary.
3693 #ifdef DEBUG_VERBOSE
3695 char *hexp, *asciip;
3696 asciip = (lastNamep? lastNamep : realPathp);
3697 hexp = osi_HexifyString( asciip );
3698 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
3703 userp = smb_GetUser(vcp, inp);
3705 osi_Log1(afsd_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
3707 return CM_ERROR_INVAL;
3711 baseDirp = cm_rootSCachep;
3712 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3715 baseFidp = smb_FindFID(vcp, baseFid, 0);
3717 osi_Log1(afsd_logp, "NTTranCreate Invalid fid [%d]", baseFid);
3719 cm_ReleaseUser(userp);
3720 return CM_ERROR_INVAL;
3722 baseDirp = baseFidp->scp;
3726 /* compute open mode */
3728 if (desiredAccess & DELETE)
3729 fidflags |= SMB_FID_OPENDELETE;
3730 if (desiredAccess & AFS_ACCESS_READ)
3731 fidflags |= SMB_FID_OPENREAD;
3732 if (desiredAccess & AFS_ACCESS_WRITE)
3733 fidflags |= SMB_FID_OPENWRITE;
3737 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3738 userp, tidPathp, &req, &scp);
3739 if (code == 0) foundscp = TRUE;
3741 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3742 /* look up parent directory */
3743 code = cm_NameI(baseDirp, spacep->data,
3744 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3745 userp, tidPathp, &req, &dscp);
3746 cm_FreeSpace(spacep);
3749 smb_ReleaseFID(baseFidp);
3754 cm_ReleaseUser(userp);
3759 if (!lastNamep) lastNamep = realPathp;
3762 if (!smb_IsLegalFilename(lastNamep))
3763 return CM_ERROR_BADNTFILENAME;
3766 code = cm_Lookup(dscp, lastNamep,
3767 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3769 if (code && code != CM_ERROR_NOSUCHFILE) {
3770 cm_ReleaseSCache(dscp);
3771 cm_ReleaseUser(userp);
3779 smb_ReleaseFID(baseFidp);