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, req8dot3 = 0;
1749 char *starNamep, *starMaskp;
1750 static char nullCharp[] = {0};
1752 /* make sure we only match 8.3 names, if requested */
1753 req8dot3 = (flags & CM_FLAG_8DOT3);
1754 if (req8dot3 && !cm_Is8Dot3(namep))
1759 /* Next pattern character */
1762 /* Next name character */
1766 /* 0 - end of pattern */
1772 else if (tcp1 == '.' || tcp1 == '"') {
1782 * first dot in pattern;
1783 * must match dot or end of name
1788 else if (tcn1 == '.') {
1797 else if (tcp1 == '?') {
1798 if (tcn1 == 0 || tcn1 == '.')
1803 else if (tcp1 == '>') {
1804 if (tcn1 != 0 && tcn1 != '.')
1808 else if (tcp1 == '*' || tcp1 == '<') {
1812 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
1813 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
1828 * pattern character after '*' is not null or
1829 * period. If it is '?' or '>', we are not
1830 * going to understand it. If it is '*' or
1831 * '<', we are going to skip over it. None of
1832 * these are likely, I hope.
1834 /* skip over '*' and '<' */
1835 while (tcp2 == '*' || tcp2 == '<')
1838 /* skip over characters that don't match tcp2 */
1839 while (req8dot3 && tcn1 != '.' && tcn1 != 0
1840 && cm_foldUpper[tcn1] != cm_foldUpper[tcp2])
1844 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
1847 /* Remember where we are */
1857 /* tcp1 is not a wildcard */
1858 if (cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) {
1863 /* if trying to match a star pattern, go back */
1865 maskp = starMaskp - 2;
1866 namep = starNamep + 1;
1876 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1885 smb_dirListPatch_t *dirListPatchesp;
1886 smb_dirListPatch_t *curPatchp;
1889 long orbytes; /* # of bytes in this output record */
1890 long ohbytes; /* # of bytes, except file name */
1891 long onbytes; /* # of bytes in name, incl. term. null */
1892 osi_hyper_t dirLength;
1893 osi_hyper_t bufferOffset;
1894 osi_hyper_t curOffset;
1896 smb_dirSearch_t *dsp;
1900 cm_pageHeader_t *pageHeaderp;
1901 cm_user_t *userp = NULL;
1904 long nextEntryCookie;
1905 int numDirChunks; /* # of 32 byte dir chunks in this entry */
1906 char *op; /* output data ptr */
1907 char *origOp; /* original value of op */
1908 cm_space_t *spacep; /* for pathname buffer */
1909 long maxReturnData; /* max # of return data */
1910 long maxReturnParms; /* max # of return parms */
1911 long bytesInBuffer; /* # data bytes in the output buffer */
1913 char *maskp; /* mask part of path */
1917 smb_tran2Packet_t *outp; /* response packet */
1920 char shortName[13]; /* 8.3 name if needed */
1931 if (p->opcode == 1) {
1932 /* find first; obtain basic parameters from request */
1933 attribute = p->parmsp[0];
1934 maxCount = p->parmsp[1];
1935 infoLevel = p->parmsp[3];
1936 searchFlags = p->parmsp[2];
1937 dsp = smb_NewDirSearch(1);
1938 dsp->attribute = attribute;
1939 pathp = ((char *) p->parmsp) + 12; /* points to path */
1941 maskp = strrchr(pathp, '\\');
1942 if (maskp == NULL) maskp = pathp;
1943 else maskp++; /* skip over backslash */
1944 strcpy(dsp->mask, maskp); /* and save mask */
1945 /* track if this is likely to match a lot of entries */
1946 starPattern = smb_V3IsStarMask(maskp);
1949 osi_assert(p->opcode == 2);
1950 /* find next; obtain basic parameters from request or open dir file */
1951 dsp = smb_FindDirSearch(p->parmsp[0]);
1952 if (!dsp) return CM_ERROR_BADFD;
1953 attribute = dsp->attribute;
1954 maxCount = p->parmsp[1];
1955 infoLevel = p->parmsp[2];
1956 searchFlags = p->parmsp[5];
1958 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
1960 starPattern = 1; /* assume, since required a Find Next */
1964 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
1965 attribute, infoLevel, maxCount, searchFlags);
1967 osi_Log2(afsd_logp, "...T2 search op %d, nextCookie 0x%x",
1968 p->opcode, nextCookie);
1970 if (infoLevel >= 0x101)
1971 searchFlags &= ~4; /* no resume keys */
1973 dirListPatchesp = NULL;
1975 maxReturnData = p->maxReturnData;
1976 if (p->opcode == 1) /* find first */
1977 maxReturnParms = 10; /* bytes */
1979 maxReturnParms = 8; /* bytes */
1981 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
1982 if (maxReturnData > 6000) maxReturnData = 6000;
1983 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
1985 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
1988 osi_Log1(afsd_logp, "T2 receive search dir %s",
1989 osi_LogSaveString(afsd_logp, pathp));
1991 /* bail out if request looks bad */
1992 if (p->opcode == 1 && !pathp) {
1993 smb_ReleaseDirSearch(dsp);
1994 smb_FreeTran2Packet(outp);
1995 return CM_ERROR_BADSMB;
1998 osi_Log2(afsd_logp, "T2 dir search cookie 0x%x, connection %d",
1999 nextCookie, dsp->cookie);
2001 userp = smb_GetTran2User(vcp, p);
2003 osi_Log1(afsd_logp, "T2 dir search unable to resolve user [%d]", p->uid);
2004 smb_ReleaseDirSearch(dsp);
2005 smb_FreeTran2Packet(outp);
2006 return CM_ERROR_BADSMB;
2009 /* try to get the vnode for the path name next */
2010 lock_ObtainMutex(&dsp->mx);
2017 spacep = cm_GetSpace();
2018 smb_StripLastComponent(spacep->data, NULL, pathp);
2019 lock_ReleaseMutex(&dsp->mx);
2021 tidPathp = smb_GetTIDPath(vcp, p->tid);
2022 code = cm_NameI(cm_rootSCachep, spacep->data,
2023 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2024 userp, tidPathp, &req, &scp);
2025 cm_FreeSpace(spacep);
2027 lock_ObtainMutex(&dsp->mx);
2029 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2031 /* we need one hold for the entry we just stored into,
2032 * and one for our own processing. When we're done
2033 * with this function, we'll drop the one for our own
2034 * processing. We held it once from the namei call,
2035 * and so we do another hold now.
2038 lock_ObtainMutex(&scp->mx);
2039 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2040 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2041 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2042 dsp->flags |= SMB_DIRSEARCH_BULKST;
2044 lock_ReleaseMutex(&scp->mx);
2047 lock_ReleaseMutex(&dsp->mx);
2049 cm_ReleaseUser(userp);
2050 smb_FreeTran2Packet(outp);
2051 smb_DeleteDirSearch(dsp);
2052 smb_ReleaseDirSearch(dsp);
2056 /* get the directory size */
2057 lock_ObtainMutex(&scp->mx);
2058 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2059 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2061 lock_ReleaseMutex(&scp->mx);
2062 cm_ReleaseSCache(scp);
2063 cm_ReleaseUser(userp);
2064 smb_FreeTran2Packet(outp);
2065 smb_DeleteDirSearch(dsp);
2066 smb_ReleaseDirSearch(dsp);
2070 dirLength = scp->length;
2072 bufferOffset.LowPart = bufferOffset.HighPart = 0;
2073 curOffset.HighPart = 0;
2074 curOffset.LowPart = nextCookie;
2075 origOp = outp->datap;
2082 if (searchFlags & 4)
2083 /* skip over resume key */
2086 /* make sure that curOffset.LowPart doesn't point to the first
2087 * 32 bytes in the 2nd through last dir page, and that it doesn't
2088 * point at the first 13 32-byte chunks in the first dir page,
2089 * since those are dir and page headers, and don't contain useful
2092 temp = curOffset.LowPart & (2048-1);
2093 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2094 /* we're in the first page */
2095 if (temp < 13*32) temp = 13*32;
2098 /* we're in a later dir page */
2099 if (temp < 32) temp = 32;
2102 /* make sure the low order 5 bits are zero */
2105 /* now put temp bits back ito curOffset.LowPart */
2106 curOffset.LowPart &= ~(2048-1);
2107 curOffset.LowPart |= temp;
2109 /* check if we've passed the dir's EOF */
2110 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2115 /* check if we've returned all the names that will fit in the
2116 * response packet; we check return count as well as the number
2117 * of bytes requested. We check the # of bytes after we find
2118 * the dir entry, since we'll need to check its size.
2120 if (returnedNames >= maxCount) {
2124 /* see if we can use the bufferp we have now; compute in which
2125 * page the current offset would be, and check whether that's
2126 * the offset of the buffer we have. If not, get the buffer.
2128 thyper.HighPart = curOffset.HighPart;
2129 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2130 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2133 buf_Release(bufferp);
2136 lock_ReleaseMutex(&scp->mx);
2137 lock_ObtainRead(&scp->bufCreateLock);
2138 code = buf_Get(scp, &thyper, &bufferp);
2139 lock_ReleaseRead(&scp->bufCreateLock);
2141 /* now, if we're doing a star match, do bulk fetching
2142 * of all of the status info for files in the dir.
2145 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2148 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2149 && LargeIntegerGreaterThanOrEqualTo(
2150 thyper, scp->bulkStatProgress)) {
2151 /* Don't bulk stat if risking timeout */
2152 int now = GetCurrentTime();
2153 if (now - req.startTime > 5000) {
2154 scp->bulkStatProgress = thyper;
2155 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2156 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2158 cm_TryBulkStat(scp, &thyper,
2163 lock_ObtainMutex(&scp->mx);
2165 bufferOffset = thyper;
2167 /* now get the data in the cache */
2169 code = cm_SyncOp(scp, bufferp, userp, &req,
2171 CM_SCACHESYNC_NEEDCALLBACK
2172 | CM_SCACHESYNC_READ);
2175 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2177 /* otherwise, load the buffer and try again */
2178 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2183 buf_Release(bufferp);
2187 } /* if (wrong buffer) ... */
2189 /* now we have the buffer containing the entry we're interested
2190 * in; copy it out if it represents a non-deleted entry.
2192 entryInDir = curOffset.LowPart & (2048-1);
2193 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2195 /* page header will help tell us which entries are free. Page
2196 * header can change more often than once per buffer, since
2197 * AFS 3 dir page size may be less than (but not more than)
2198 * a buffer package buffer.
2200 /* only look intra-buffer */
2201 temp = curOffset.LowPart & (buf_bufferSize - 1);
2202 temp &= ~(2048 - 1); /* turn off intra-page bits */
2203 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2205 /* now determine which entry we're looking at in the page.
2206 * If it is free (there's a free bitmap at the start of the
2207 * dir), we should skip these 32 bytes.
2209 slotInPage = (entryInDir & 0x7e0) >> 5;
2210 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2211 & (1 << (slotInPage & 0x7)))) {
2212 /* this entry is free */
2213 numDirChunks = 1; /* only skip this guy */
2217 tp = bufferp->datap + entryInBuffer;
2218 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
2220 /* while we're here, compute the next entry's location, too,
2221 * since we'll need it when writing out the cookie into the dir
2224 * XXXX Probably should do more sanity checking.
2226 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2228 /* compute offset of cookie representing next entry */
2229 nextEntryCookie = curOffset.LowPart
2230 + (CM_DIR_CHUNKSIZE * numDirChunks);
2232 /* Need 8.3 name? */
2234 if (infoLevel == 0x104
2235 && dep->fid.vnode != 0
2236 && !cm_Is8Dot3(dep->name)) {
2237 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2241 if (dep->fid.vnode != 0
2242 && (smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)
2244 && smb_V3MatchMask(shortName, maskp,
2245 CM_FLAG_CASEFOLD)))) {
2247 /* Eliminate entries that don't match requested
2249 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
2250 smb_IsDotFile(dep->name))
2251 goto nextEntry; /* no hidden files */
2253 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
2255 /* We have already done the cm_TryBulkStat above */
2256 fid.cell = scp->fid.cell;
2257 fid.volume = scp->fid.volume;
2258 fid.vnode = ntohl(dep->fid.vnode);
2259 fid.unique = ntohl(dep->fid.unique);
2260 fileType = cm_FindFileType(&fid);
2261 /*osi_Log2(afsd_logp, "smb_ReceiveTran2SearchDir: file %s "
2262 "has filetype %d", dep->name,
2264 if (fileType == CM_SCACHETYPE_DIRECTORY)
2268 /* finally check if this name will fit */
2270 /* standard dir entry stuff */
2271 if (infoLevel < 0x101)
2272 ohbytes = 23; /* pre-NT */
2273 else if (infoLevel == 0x103)
2274 ohbytes = 12; /* NT names only */
2276 ohbytes = 64; /* NT */
2278 if (infoLevel == 0x104)
2279 ohbytes += 26; /* Short name & length */
2281 if (searchFlags & 4) {
2282 ohbytes += 4; /* if resume key required */
2286 && infoLevel != 0x101
2287 && infoLevel != 0x103)
2288 ohbytes += 4; /* EASIZE */
2290 /* add header to name & term. null */
2291 orbytes = onbytes + ohbytes + 1;
2293 /* now, we round up the record to a 4 byte alignment,
2294 * and we make sure that we have enough room here for
2295 * even the aligned version (so we don't have to worry
2296 * about an * overflow when we pad things out below).
2297 * That's the reason for the alignment arithmetic below.
2299 if (infoLevel >= 0x101)
2300 align = (4 - (orbytes & 3)) & 3;
2303 if (orbytes + bytesInBuffer + align > maxReturnData)
2306 /* this is one of the entries to use: it is not deleted
2307 * and it matches the star pattern we're looking for.
2308 * Put out the name, preceded by its length.
2310 /* First zero everything else */
2311 memset(origOp, 0, ohbytes);
2313 if (infoLevel <= 0x101)
2314 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2315 else if (infoLevel == 0x103)
2316 *((u_long *)(op + 8)) = onbytes;
2318 *((u_long *)(op + 60)) = onbytes;
2319 strcpy(origOp+ohbytes, dep->name);
2321 /* Short name if requested and needed */
2322 if (infoLevel == 0x104) {
2323 if (NeedShortName) {
2324 strcpy(op + 70, shortName);
2325 *(op + 68) = shortNameEnd - shortName;
2329 /* now, adjust the # of entries copied */
2332 /* NextEntryOffset and FileIndex */
2333 if (infoLevel >= 101) {
2334 int entryOffset = orbytes + align;
2335 *((u_long *)op) = entryOffset;
2336 *((u_long *)(op+4)) = nextEntryCookie;
2339 /* now we emit the attribute. This is tricky, since
2340 * we need to really stat the file to find out what
2341 * type of entry we've got. Right now, we're copying
2342 * out data from * a buffer, while holding the scp
2343 * locked, so it isn't really convenient to stat
2344 * something now. We'll put in a place holder
2345 * now, and make a second pass before returning this
2346 * to get the real attributes. So, we just skip the
2347 * data for now, and adjust it later. We allocate a
2348 * patch record to make it easy to find this point
2349 * later. The replay will happen at a time when it is
2350 * safe to unlock the directory.
2352 if (infoLevel != 0x103) {
2353 curPatchp = malloc(sizeof(*curPatchp));
2354 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2356 curPatchp->dptr = op;
2357 if (infoLevel >= 0x101)
2358 curPatchp->dptr += 8;
2360 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
2361 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
2364 curPatchp->flags = 0;
2366 curPatchp->fid.cell = scp->fid.cell;
2367 curPatchp->fid.volume = scp->fid.volume;
2368 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2369 curPatchp->fid.unique = ntohl(dep->fid.unique);
2372 curPatchp->dep = dep;
2375 if (searchFlags & 4)
2376 /* put out resume key */
2377 *((u_long *)origOp) = nextEntryCookie;
2379 /* Adjust byte ptr and count */
2380 origOp += orbytes; /* skip entire record */
2381 bytesInBuffer += orbytes;
2383 /* and pad the record out */
2384 while (--align >= 0) {
2389 } /* if we're including this name */
2392 /* and adjust curOffset to be where the new cookie is */
2393 thyper.HighPart = 0;
2394 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2395 curOffset = LargeIntegerAdd(thyper, curOffset);
2396 } /* while copying data for dir listing */
2398 /* release the mutex */
2399 lock_ReleaseMutex(&scp->mx);
2400 if (bufferp) buf_Release(bufferp);
2402 /* apply and free last set of patches; if not doing a star match, this
2403 * will be empty, but better safe (and freeing everything) than sorry.
2405 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2408 /* now put out the final parameters */
2409 if (returnedNames == 0) eos = 1;
2410 if (p->opcode == 1) {
2412 outp->parmsp[0] = (unsigned short) dsp->cookie;
2413 outp->parmsp[1] = returnedNames;
2414 outp->parmsp[2] = eos;
2415 outp->parmsp[3] = 0; /* nothing wrong with EAS */
2416 outp->parmsp[4] = 0; /* don't need last name to continue
2417 * search, cookie is enough. Normally,
2418 * this is the offset of the file name
2419 * of the last entry returned.
2421 outp->totalParms = 10; /* in bytes */
2425 outp->parmsp[0] = returnedNames;
2426 outp->parmsp[1] = eos;
2427 outp->parmsp[2] = 0; /* EAS error */
2428 outp->parmsp[3] = 0; /* last name, as above */
2429 outp->totalParms = 8; /* in bytes */
2432 /* return # of bytes in the buffer */
2433 outp->totalData = bytesInBuffer;
2435 osi_Log2(afsd_logp, "T2 search dir done, %d names, code %d",
2436 returnedNames, code);
2438 /* Return error code if unsuccessful on first request */
2439 if (code == 0 && p->opcode == 1 && returnedNames == 0)
2440 code = CM_ERROR_NOSUCHFILE;
2442 /* if we're supposed to close the search after this request, or if
2443 * we're supposed to close the search if we're done, and we're done,
2444 * or if something went wrong, close the search.
2446 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2447 if ((searchFlags & 1) || (returnedNames == 0) || ((searchFlags & 2) &&
2449 smb_DeleteDirSearch(dsp);
2451 smb_SendTran2Error(vcp, p, opx, code);
2453 smb_SendTran2Packet(vcp, outp, opx);
2455 smb_FreeTran2Packet(outp);
2456 smb_ReleaseDirSearch(dsp);
2457 cm_ReleaseSCache(scp);
2458 cm_ReleaseUser(userp);
2462 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2465 smb_dirSearch_t *dsp;
2467 dirHandle = smb_GetSMBParm(inp, 0);
2469 osi_Log1(afsd_logp, "SMB3 find close handle %d", dirHandle);
2471 dsp = smb_FindDirSearch(dirHandle);
2474 return CM_ERROR_BADFD;
2476 /* otherwise, we have an FD to destroy */
2477 smb_DeleteDirSearch(dsp);
2478 smb_ReleaseDirSearch(dsp);
2480 /* and return results */
2481 smb_SetSMBDataLength(outp, 0);
2486 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2488 smb_SetSMBDataLength(outp, 0);
2492 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2499 cm_scache_t *dscp; /* dir we're dealing with */
2500 cm_scache_t *scp; /* file we're creating */
2502 int initialModeBits;
2512 int parmSlot; /* which parm we're dealing with */
2520 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
2521 openFun = smb_GetSMBParm(inp, 8); /* open function */
2522 excl = ((openFun & 3) == 0);
2523 trunc = ((openFun & 3) == 2); /* truncate it */
2524 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2525 openAction = 0; /* tracks what we did */
2527 attributes = smb_GetSMBParm(inp, 5);
2528 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2530 /* compute initial mode bits based on read-only flag in attributes */
2531 initialModeBits = 0666;
2532 if (attributes & 1) initialModeBits &= ~0222;
2534 pathp = smb_GetSMBData(inp, NULL);
2536 spacep = inp->spacep;
2537 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2539 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2540 /* special case magic file name for receiving IOCTL requests
2541 * (since IOCTL calls themselves aren't getting through).
2544 osi_Log0(afsd_logp, "IOCTL Open");
2547 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2548 smb_SetupIoctlFid(fidp, spacep);
2550 /* set inp->fid so that later read calls in same msg can find fid */
2551 inp->fid = fidp->fid;
2553 /* copy out remainder of the parms */
2555 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2557 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2558 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
2559 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2560 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
2561 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2562 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2563 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2564 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2566 /* and the final "always present" stuff */
2567 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2568 /* next write out the "unique" ID */
2569 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2570 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2571 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2572 smb_SetSMBDataLength(outp, 0);
2574 /* and clean up fid reference */
2575 smb_ReleaseFID(fidp);
2579 #ifdef DEBUG_VERBOSE
2581 char *hexp, *asciip;
2582 asciip = (lastNamep ? lastNamep : pathp );
2583 hexp = osi_HexifyString(asciip);
2584 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
2588 userp = smb_GetUser(vcp, inp);
2591 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2592 code = cm_NameI(cm_rootSCachep, pathp,
2593 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2594 userp, tidPathp, &req, &scp);
2596 code = cm_NameI(cm_rootSCachep, spacep->data,
2597 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2598 userp, tidPathp, &req, &dscp);
2601 cm_ReleaseUser(userp);
2605 /* otherwise, scp points to the parent directory. Do a lookup,
2606 * and truncate the file if we find it, otherwise we create the
2609 if (!lastNamep) lastNamep = pathp;
2611 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2613 if (code && code != CM_ERROR_NOSUCHFILE) {
2614 cm_ReleaseSCache(dscp);
2615 cm_ReleaseUser(userp);
2620 /* if we get here, if code is 0, the file exists and is represented by
2621 * scp. Otherwise, we have to create it. The dir may be represented
2622 * by dscp, or we may have found the file directly. If code is non-zero,
2626 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2628 if (dscp) cm_ReleaseSCache(dscp);
2629 cm_ReleaseSCache(scp);
2630 cm_ReleaseUser(userp);
2635 /* oops, file shouldn't be there */
2636 if (dscp) cm_ReleaseSCache(dscp);
2637 cm_ReleaseSCache(scp);
2638 cm_ReleaseUser(userp);
2639 return CM_ERROR_EXISTS;
2643 setAttr.mask = CM_ATTRMASK_LENGTH;
2644 setAttr.length.LowPart = 0;
2645 setAttr.length.HighPart = 0;
2646 code = cm_SetAttr(scp, &setAttr, userp, &req);
2647 openAction = 3; /* truncated existing file */
2649 else openAction = 1; /* found existing file */
2651 else if (!(openFun & 0x10)) {
2652 /* don't create if not found */
2653 if (dscp) cm_ReleaseSCache(dscp);
2654 cm_ReleaseUser(userp);
2655 return CM_ERROR_NOSUCHFILE;
2658 osi_assert(dscp != NULL);
2659 osi_Log1(afsd_logp, "smb_ReceiveV3OpenX creating file %s",
2660 osi_LogSaveString(afsd_logp, lastNamep));
2661 openAction = 2; /* created file */
2662 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2663 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2664 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2666 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2667 smb_NotifyChange(FILE_ACTION_ADDED,
2668 FILE_NOTIFY_CHANGE_FILE_NAME,
2669 dscp, lastNamep, NULL, TRUE);
2670 if (!excl && code == CM_ERROR_EXISTS) {
2671 /* not an exclusive create, and someone else tried
2672 * creating it already, then we open it anyway. We
2673 * don't bother retrying after this, since if this next
2674 * fails, that means that the file was deleted after we
2675 * started this call.
2677 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2681 setAttr.mask = CM_ATTRMASK_LENGTH;
2682 setAttr.length.LowPart = 0;
2683 setAttr.length.HighPart = 0;
2684 code = cm_SetAttr(scp, &setAttr, userp, &req);
2686 } /* lookup succeeded */
2690 /* we don't need this any longer */
2691 if (dscp) cm_ReleaseSCache(dscp);
2694 /* something went wrong creating or truncating the file */
2695 if (scp) cm_ReleaseSCache(scp);
2696 cm_ReleaseUser(userp);
2700 /* make sure we're about to open a file */
2701 if (scp->fileType != CM_SCACHETYPE_FILE) {
2702 cm_ReleaseSCache(scp);
2703 cm_ReleaseUser(userp);
2704 return CM_ERROR_ISDIR;
2707 /* now all we have to do is open the file itself */
2708 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2711 /* save a pointer to the vnode */
2714 /* compute open mode */
2715 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2716 if (openMode == 1 || openMode == 2)
2717 fidp->flags |= SMB_FID_OPENWRITE;
2719 smb_ReleaseFID(fidp);
2721 cm_Open(scp, 0, userp);
2723 /* set inp->fid so that later read calls in same msg can find fid */
2724 inp->fid = fidp->fid;
2726 /* copy out remainder of the parms */
2728 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2729 lock_ObtainMutex(&scp->mx);
2731 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2732 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2733 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2734 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2735 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2736 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2737 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2738 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2739 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2741 /* and the final "always present" stuff */
2742 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2743 /* next write out the "unique" ID */
2744 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2745 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2746 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2747 lock_ReleaseMutex(&scp->mx);
2748 smb_SetSMBDataLength(outp, 0);
2750 osi_Log1(afsd_logp, "SMB OpenX opening fid %d", fidp->fid);
2752 cm_ReleaseUser(userp);
2753 /* leave scp held since we put it in fidp->scp */
2757 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2764 unsigned char LockType;
2765 unsigned short NumberOfUnlocks, NumberOfLocks;
2766 unsigned long Timeout;
2768 LARGE_INTEGER LOffset, LLength;
2769 smb_waitingLock_t *waitingLock;
2776 fid = smb_GetSMBParm(inp, 2);
2777 fid = smb_ChainFID(fid, inp);
2779 fidp = smb_FindFID(vcp, fid, 0);
2780 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2781 return CM_ERROR_BADFD;
2783 /* set inp->fid so that later read calls in same msg can find fid */
2786 userp = smb_GetUser(vcp, inp);
2790 lock_ObtainMutex(&scp->mx);
2791 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2792 CM_SCACHESYNC_NEEDCALLBACK
2793 | CM_SCACHESYNC_GETSTATUS
2794 | CM_SCACHESYNC_LOCK);
2795 if (code) goto doneSync;
2797 LockType = smb_GetSMBParm(inp, 3) & 0xff;
2798 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2799 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2800 NumberOfLocks = smb_GetSMBParm(inp, 7);
2802 op = smb_GetSMBData(inp, NULL);
2804 for (i=0; i<NumberOfUnlocks; i++) {
2805 if (LockType & 0x10) {
2807 LOffset.HighPart = *((LONG *)(op + 4));
2808 LOffset.LowPart = *((DWORD *)(op + 8));
2809 LLength.HighPart = *((LONG *)(op + 12));
2810 LLength.LowPart = *((DWORD *)(op + 16));
2814 /* Not Large Files */
2815 LOffset.HighPart = 0;
2816 LOffset.LowPart = *((DWORD *)(op + 2));
2817 LLength.HighPart = 0;
2818 LLength.LowPart = *((DWORD *)(op + 6));
2821 if (LargeIntegerNotEqualToZero(LOffset))
2823 /* Do not check length -- length check done in cm_Unlock */
2825 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2826 if (code) goto done;
2829 for (i=0; i<NumberOfLocks; i++) {
2830 if (LockType & 0x10) {
2832 LOffset.HighPart = *((LONG *)(op + 4));
2833 LOffset.LowPart = *((DWORD *)(op + 8));
2834 LLength.HighPart = *((LONG *)(op + 12));
2835 LLength.LowPart = *((DWORD *)(op + 16));
2839 /* Not Large Files */
2840 LOffset.HighPart = 0;
2841 LOffset.LowPart = *((DWORD *)(op + 2));
2842 LLength.HighPart = 0;
2843 LLength.LowPart = *((DWORD *)(op + 6));
2846 if (LargeIntegerNotEqualToZero(LOffset))
2848 if (LargeIntegerLessThan(LOffset, scp->length))
2851 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2852 userp, &req, &lockp);
2853 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2854 /* Put on waiting list */
2855 waitingLock = malloc(sizeof(smb_waitingLock_t));
2856 waitingLock->vcp = vcp;
2857 waitingLock->inp = smb_CopyPacket(inp);
2858 waitingLock->outp = smb_CopyPacket(outp);
2859 waitingLock->timeRemaining = Timeout;
2860 waitingLock->lockp = lockp;
2861 lock_ObtainWrite(&smb_globalLock);
2862 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2864 osi_Wakeup((long) &smb_allWaitingLocks);
2865 lock_ReleaseWrite(&smb_globalLock);
2866 /* don't send reply immediately */
2867 outp->flags |= SMB_PACKETFLAG_NOSEND;
2873 /* release any locks acquired before the failure */
2876 smb_SetSMBDataLength(outp, 0);
2878 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2880 lock_ReleaseMutex(&scp->mx);
2881 cm_ReleaseUser(userp);
2882 smb_ReleaseFID(fidp);
2887 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2899 fid = smb_GetSMBParm(inp, 0);
2900 fid = smb_ChainFID(fid, inp);
2902 fidp = smb_FindFID(vcp, fid, 0);
2903 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2904 return CM_ERROR_BADFD;
2907 userp = smb_GetUser(vcp, inp);
2911 /* otherwise, stat the file */
2912 lock_ObtainMutex(&scp->mx);
2913 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2914 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2915 if (code) goto done;
2917 /* decode times. We need a search time, but the response to this
2918 * call provides the date first, not the time, as returned in the
2919 * searchTime variable. So we take the high-order bits first.
2921 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2922 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
2923 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2924 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
2925 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2926 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
2927 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2929 /* now handle file size and allocation size */
2930 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
2931 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2932 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
2933 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2935 /* file attribute */
2936 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2938 /* and finalize stuff */
2939 smb_SetSMBDataLength(outp, 0);
2943 lock_ReleaseMutex(&scp->mx);
2944 cm_ReleaseUser(userp);
2945 smb_ReleaseFID(fidp);
2949 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2963 fid = smb_GetSMBParm(inp, 0);
2964 fid = smb_ChainFID(fid, inp);
2966 fidp = smb_FindFID(vcp, fid, 0);
2967 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2968 return CM_ERROR_BADFD;
2971 userp = smb_GetUser(vcp, inp);
2975 /* now prepare to call cm_setattr. This message only sets various times,
2976 * and AFS only implements mtime, and we'll set the mtime if that's
2977 * requested. The others we'll ignore.
2979 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
2981 if (searchTime != 0) {
2982 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
2984 if ( unixTime != -1 ) {
2985 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
2986 attrs.clientModTime = unixTime;
2987 code = cm_SetAttr(scp, &attrs, userp, &req);
2989 osi_Log1(afsd_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
2991 osi_Log1(afsd_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
2996 cm_ReleaseUser(userp);
2997 smb_ReleaseFID(fidp);
3002 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3005 long count, finalCount;
3012 fd = smb_GetSMBParm(inp, 2);
3013 count = smb_GetSMBParm(inp, 5);
3014 offset.HighPart = 0; /* too bad */
3015 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
3017 osi_Log3(afsd_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
3018 fd, offset.LowPart, count);
3020 fd = smb_ChainFID(fd, inp);
3021 fidp = smb_FindFID(vcp, fd, 0);
3023 return CM_ERROR_BADFD;
3025 /* set inp->fid so that later read calls in same msg can find fid */
3028 if (fidp->flags & SMB_FID_IOCTL) {
3029 return smb_IoctlV3Read(fidp, vcp, inp, outp);
3032 userp = smb_GetUser(vcp, inp);
3034 /* 0 and 1 are reserved for request chaining, were setup by our caller,
3035 * and will be further filled in after we return.
3037 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
3038 smb_SetSMBParm(outp, 3, 0); /* resvd */
3039 smb_SetSMBParm(outp, 4, 0); /* resvd */
3040 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
3041 /* fill in #6 when we have all the parameters' space reserved */
3042 smb_SetSMBParm(outp, 7, 0); /* resv'd */
3043 smb_SetSMBParm(outp, 8, 0); /* resv'd */
3044 smb_SetSMBParm(outp, 9, 0); /* resv'd */
3045 smb_SetSMBParm(outp, 10, 0); /* resv'd */
3046 smb_SetSMBParm(outp, 11, 0); /* reserved */
3048 /* get op ptr after putting in the parms, since otherwise we don't
3049 * know where the data really is.
3051 op = smb_GetSMBData(outp, NULL);
3053 /* now fill in offset from start of SMB header to first data byte (to op) */
3054 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
3056 /* set the packet data length the count of the # of bytes */
3057 smb_SetSMBDataLength(outp, count);
3060 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
3062 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
3065 /* fix some things up */
3066 smb_SetSMBParm(outp, 5, finalCount);
3067 smb_SetSMBDataLength(outp, finalCount);
3069 smb_ReleaseFID(fidp);
3071 cm_ReleaseUser(userp);
3076 * Values for createDisp, copied from NTDDK.H
3078 * FILE_SUPERSEDE 0 (???)
3079 * FILE_OPEN 1 (open)
3080 * FILE_CREATE 2 (exclusive)
3081 * FILE_OPEN_IF 3 (non-exclusive)
3082 * FILE_OVERWRITE 4 (open & truncate, but do not create)
3083 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
3086 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3088 char *pathp, *realPathp;
3092 cm_scache_t *dscp; /* parent dir */
3093 cm_scache_t *scp; /* file to create or open */
3097 unsigned short nameLength;
3099 unsigned int requestOpLock;
3100 unsigned int requestBatchOpLock;
3101 unsigned int mustBeDir;
3102 unsigned int treeCreate;
3104 unsigned int desiredAccess;
3105 unsigned int extAttributes;
3106 unsigned int createDisp;
3107 unsigned int createOptions;
3108 int initialModeBits;
3109 unsigned short baseFid;
3110 smb_fid_t *baseFidp;
3112 cm_scache_t *baseDirp;
3113 unsigned short openAction;
3128 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3129 flags = smb_GetSMBOffsetParm(inp, 3, 1)
3130 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3131 requestOpLock = flags & 0x02;
3132 requestBatchOpLock = flags & 0x04;
3133 mustBeDir = flags & 0x08;
3136 * Why all of a sudden 32-bit FID?
3137 * We will reject all bits higher than 16.
3139 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3140 return CM_ERROR_INVAL;
3141 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3142 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3143 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3144 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3145 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3146 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3147 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3148 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3149 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3151 /* mustBeDir is never set; createOptions directory bit seems to be
3154 if (createOptions & 1)
3156 else if (createOptions & 0x40)
3162 * compute initial mode bits based on read-only flag in
3163 * extended attributes
3165 initialModeBits = 0666;
3166 if (extAttributes & 1) initialModeBits &= ~0222;
3168 pathp = smb_GetSMBData(inp, NULL);
3169 /* Sometimes path is not null-terminated, so we make a copy. */
3170 realPathp = malloc(nameLength+1);
3171 memcpy(realPathp, pathp, nameLength);
3172 realPathp[nameLength] = 0;
3174 spacep = inp->spacep;
3175 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3177 osi_Log1(afsd_logp,"NTCreateX for [%s]",osi_LogSaveString(afsd_logp,realPathp));
3178 osi_Log4(afsd_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
3180 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3181 /* special case magic file name for receiving IOCTL requests
3182 * (since IOCTL calls themselves aren't getting through).
3184 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3185 smb_SetupIoctlFid(fidp, spacep);
3187 /* set inp->fid so that later read calls in same msg can find fid */
3188 inp->fid = fidp->fid;
3192 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3193 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3194 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3196 memset(&ft, 0, sizeof(ft));
3197 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3198 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3199 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3200 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3201 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3202 sz.HighPart = 0x7fff; sz.LowPart = 0;
3203 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3204 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3205 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3206 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3207 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
3208 smb_SetSMBDataLength(outp, 0);
3210 /* clean up fid reference */
3211 smb_ReleaseFID(fidp);
3216 #ifdef DEBUG_VERBOSE
3218 char *hexp, *asciip;
3219 asciip = (lastNamep? lastNamep : realPathp);
3220 hexp = osi_HexifyString( asciip );
3221 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
3225 userp = smb_GetUser(vcp, inp);
3227 osi_Log1(afsd_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
3229 return CM_ERROR_INVAL;
3233 baseDirp = cm_rootSCachep;
3234 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3237 baseFidp = smb_FindFID(vcp, baseFid, 0);
3239 osi_Log1(afsd_logp, "NTCreateX Invalid base fid [%d]", baseFid);
3241 cm_ReleaseUser(userp);
3242 return CM_ERROR_INVAL;
3244 baseDirp = baseFidp->scp;
3248 osi_Log1(afsd_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(afsd_logp,tidPathp));
3250 /* compute open mode */
3252 if (desiredAccess & DELETE)
3253 fidflags |= SMB_FID_OPENDELETE;
3254 if (desiredAccess & AFS_ACCESS_READ)
3255 fidflags |= SMB_FID_OPENREAD;
3256 if (desiredAccess & AFS_ACCESS_WRITE)
3257 fidflags |= SMB_FID_OPENWRITE;
3261 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3262 userp, tidPathp, &req, &scp);
3263 if (code == 0) foundscp = TRUE;
3265 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3266 /* look up parent directory */