case-sensitivity-20040506
[openafs.git] / src / WINNT / afsd / smb3.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #ifndef DJGPP
14 #include <windows.h>
15 #endif /* !DJGPP */
16 #include <stdlib.h>
17 #include <malloc.h>
18 #include <string.h>
19 #include <stdio.h>
20 #include <time.h>
21
22 #include <osi.h>
23
24 #include "afsd.h"
25
26 #include "smb.h"
27
28 extern osi_hyper_t hzero;
29
30 smb_packet_t *smb_Directory_Watches = NULL;
31 osi_mutex_t smb_Dir_Watch_Lock;
32
33 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
34
35 /* protected by the smb_globalLock */
36 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
37
38 /* retrieve a held reference to a user structure corresponding to an incoming
39  * request */
40 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
41 {
42         smb_user_t *uidp;
43     cm_user_t *up = NULL;
44         
45     uidp = smb_FindUID(vcp, inp->uid, 0);
46     if (!uidp) return NULL;
47         
48         lock_ObtainMutex(&uidp->mx);
49     if (uidp->unp) {
50         up = uidp->unp->userp;
51         cm_HoldUser(up);
52     }
53         lock_ReleaseMutex(&uidp->mx);
54
55     smb_ReleaseUID(uidp);
56
57     return up;
58 }
59
60 /*
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).
64  */
65 unsigned long smb_ExtAttributes(cm_scache_t *scp)
66 {
67         unsigned long attrs;
68
69         if (scp->fileType == CM_SCACHETYPE_DIRECTORY
70             || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
71                 attrs = SMB_ATTR_DIRECTORY;
72         else
73                 attrs = 0;
74         /*
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.
77          */
78 #ifdef notdef
79         if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
80 #endif
81         if ((scp->unixModeBits & 0222) == 0)
82                 attrs |= SMB_ATTR_READONLY;             /* Read-only */
83
84         if (attrs == 0)
85                 attrs = SMB_ATTR_NORMAL;                /* FILE_ATTRIBUTE_NORMAL */
86
87         return attrs;
88 }
89
90 int smb_V3IsStarMask(char *maskp)
91 {
92     char tc;
93
94         while (tc = *maskp++)
95         if (tc == '?' || tc == '*') 
96             return 1;
97         return 0;
98 }
99
100 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
101 {
102     if (chainpp) {
103                 /* skip over null-terminated string */
104                 *chainpp = inp + strlen(inp) + 1;
105     }
106     return inp;
107 }   
108
109 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
110 {
111     char *tp;
112     char *usern, *pwd, *pwdx;
113     smb_user_t *uidp;
114     unsigned short newUid;
115     unsigned long caps;
116     cm_user_t *userp;
117     smb_username_t *unp;
118     char *s1 = " ";
119
120     /* Check for bad conns */
121     if (vcp->flags & SMB_VCFLAG_REMOTECONN)
122         return CM_ERROR_REMOTECONN;
123
124     /* For NT LM 0.12 and up, get capabilities */
125     if (vcp->flags & SMB_VCFLAG_USENT) {
126         caps = smb_GetSMBParm(inp, 11);
127         if (caps & 0x40)
128             vcp->flags |= SMB_VCFLAG_STATUS32;
129         /* for now, ignore other capability bits */
130     }
131
132     /* Parse the data */
133     tp = smb_GetSMBData(inp, NULL);
134     if (vcp->flags & SMB_VCFLAG_USENT)
135         pwdx = smb_ParseString(tp, &tp);
136     pwd = smb_ParseString(tp, &tp);
137     usern = smb_ParseString(tp, &tp);
138
139     /* On Windows 2000, this function appears to be called more often than
140        it is expected to be called. This resulted in multiple smb_user_t
141        records existing all for the same user session which results in all
142        of the users tokens disappearing.
143
144        To avoid this problem, we look for an existing smb_user_t record
145        based on the users name, and use that one if we find it.
146     */
147
148     uidp = smb_FindUserByNameThisSession(vcp, usern);
149     if (uidp) {   /* already there, so don't create a new one */
150         unp = uidp->unp;
151         userp = unp->userp;
152         newUid = (unsigned short)uidp->userID;  /* For some reason these are different types!*/
153                 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,usern);
154                 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
155         smb_ReleaseUID(uidp);
156     }
157     else {
158       /* do a global search for the username/machine name pair */
159         unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
160
161         /* Create a new UID and cm_user_t structure */
162         userp = unp->userp;
163         if (!userp)
164             userp = cm_NewUser();
165         lock_ObtainMutex(&vcp->mx);
166         if (!vcp->uidCounter)
167             vcp->uidCounter++; /* handle unlikely wraparounds */
168         newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
169         lock_ReleaseMutex(&vcp->mx);
170
171         /* Create a new smb_user_t structure and connect them up */
172         lock_ObtainMutex(&unp->mx);
173         unp->userp = userp;
174         lock_ReleaseMutex(&unp->mx);
175
176         uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
177         lock_ObtainMutex(&uidp->mx);
178         uidp->unp = unp;
179                 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",(int)vcp,vcp->lana,vcp->lsn,newUid,usern);
180                 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
181         lock_ReleaseMutex(&uidp->mx);
182         smb_ReleaseUID(uidp);
183     }
184
185     /* Return UID to the client */
186     ((smb_t *)outp)->uid = newUid;
187     /* Also to the next chained message */
188     ((smb_t *)inp)->uid = newUid;
189
190     osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
191              osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
192     smb_SetSMBParm(outp, 2, 0);
193     smb_SetSMBDataLength(outp, 0);
194     return 0;
195 }
196
197 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
198 {
199         smb_user_t *uidp;
200
201         /* don't get tokens from this VC */
202         vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
203
204         inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
205
206         /* find the tree and free it */
207     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
208     /* TODO: smb_ReleaseUID() ? */
209     if (uidp) {
210                 char *s1 = NULL, *s2 = NULL;
211
212                 if (s2 == NULL) s2 = " ";
213                 if (s1 == NULL) {s1 = s2; s2 = " ";}
214
215                 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s",
216                   uidp->userID,
217                   osi_LogSaveString(smb_logp,
218                                     (uidp->unp) ? uidp->unp->name: " "), s1, s2);
219
220                 lock_ObtainMutex(&uidp->mx);
221                 uidp->flags |= SMB_USERFLAG_DELETE;
222                 /*
223                  * it doesn't get deleted right away
224                  * because the vcp points to it
225                  */
226         lock_ReleaseMutex(&uidp->mx);
227     }
228         else    
229                 osi_Log0(smb_logp, "SMB3 user logoffX");
230
231     smb_SetSMBDataLength(outp, 0);
232     return 0;
233 }
234
235 #define SMB_SUPPORT_SEARCH_BITS        0x0001
236
237 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
238 {
239     smb_tid_t *tidp;
240     unsigned short newTid;
241     char shareName[256];
242         char *sharePath;
243         int shareFound;
244     char *tp;
245     char *pathp;
246     char *passwordp;
247         char *servicep;
248     cm_user_t *userp;
249         
250         osi_Log0(smb_logp, "SMB3 receive tree connect");
251
252         /* parse input parameters */
253         tp = smb_GetSMBData(inp, NULL);
254     passwordp = smb_ParseString(tp, &tp);
255         pathp = smb_ParseString(tp, &tp);
256         servicep = smb_ParseString(tp, &tp);
257
258         tp = strrchr(pathp, '\\');
259     if (!tp) {
260         return CM_ERROR_BADSMB;
261     }
262     strcpy(shareName, tp+1);
263
264         if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0)
265                 return CM_ERROR_NOIPC;
266
267     userp = smb_GetUser(vcp, inp);
268
269         lock_ObtainMutex(&vcp->mx);
270     newTid = vcp->tidCounter++;
271         lock_ReleaseMutex(&vcp->mx);
272         
273         tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
274         shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
275         if (!shareFound) {
276                 smb_ReleaseTID(tidp);
277                 return CM_ERROR_BADSHARENAME;
278         }
279     lock_ObtainMutex(&tidp->mx);
280     tidp->userp = userp;
281         tidp->pathname = sharePath;
282     lock_ReleaseMutex(&tidp->mx);
283     smb_ReleaseTID(tidp);
284
285         if (vcp->flags & SMB_VCFLAG_USENT)
286     {
287         int policy = smb_FindShareCSCPolicy(shareName);
288         smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy << 2));
289     }
290
291         ((smb_t *)outp)->tid = newTid;
292         ((smb_t *)inp)->tid = newTid;
293         tp = smb_GetSMBData(outp, NULL);
294     *tp++ = 'A';
295     *tp++ = ':';
296     *tp++ = 0;
297     smb_SetSMBDataLength(outp, 3);
298
299     osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
300     return 0;
301 }
302
303 /* must be called with global tran lock held */
304 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
305 {
306         smb_tran2Packet_t *tp;
307     smb_t *smbp;
308         
309     smbp = (smb_t *) inp->data;
310         for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
311                 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
312             return tp;
313     }
314     return NULL;
315 }
316
317 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
318         int totalParms, int totalData)
319 {
320         smb_tran2Packet_t *tp;
321     smb_t *smbp;
322         
323     smbp = (smb_t *) inp->data;
324         tp = malloc(sizeof(*tp));
325     memset(tp, 0, sizeof(*tp));
326     tp->vcp = vcp;
327     smb_HoldVC(vcp);
328     tp->curData = tp->curParms = 0;
329     tp->totalData = totalData;
330     tp->totalParms = totalParms;
331     tp->tid = smbp->tid;
332     tp->mid = smbp->mid;
333     tp->uid = smbp->uid;
334     tp->pid = smbp->pid;
335         tp->res[0] = smbp->res[0];
336         osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
337     tp->opcode = smb_GetSMBParm(inp, 14);
338         if (totalParms != 0)
339         tp->parmsp = malloc(totalParms);
340         if (totalData != 0)
341         tp->datap = malloc(totalData);
342         tp->flags |= SMB_TRAN2PFLAG_ALLOC;
343     return tp;
344 }
345
346 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
347         smb_tran2Packet_t *inp, smb_packet_t *outp,
348         int totalParms, int totalData)
349 {
350         smb_tran2Packet_t *tp;
351         unsigned short parmOffset;
352         unsigned short dataOffset;
353         unsigned short dataAlign;
354         
355         tp = malloc(sizeof(*tp));
356     memset(tp, 0, sizeof(*tp));
357     tp->vcp = NULL;
358     tp->curData = tp->curParms = 0;
359     tp->totalData = totalData;
360     tp->totalParms = totalParms;
361         tp->oldTotalParms = totalParms;
362     tp->tid = inp->tid;
363     tp->mid = inp->mid;
364     tp->uid = inp->uid;
365     tp->pid = inp->pid;
366         tp->res[0] = inp->res[0];
367     tp->opcode = inp->opcode;
368
369         /*
370          * We calculate where the parameters and data will start.
371          * This calculation must parallel the calculation in
372          * smb_SendTran2Packet.
373          */
374
375         parmOffset = 10*2 + 35;
376         parmOffset++;                   /* round to even */
377         tp->parmsp = (unsigned short *) (outp->data + parmOffset);
378
379         dataOffset = parmOffset + totalParms;
380         dataAlign = dataOffset & 2;     /* quad-align */
381         dataOffset += dataAlign;
382         tp->datap = outp->data + dataOffset;
383
384     return tp;
385 }
386
387 /* free a tran2 packet; must be called with smb_globalLock held */
388 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
389 {
390     if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
391         if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
392                 if (t2p->parmsp)
393                         free(t2p->parmsp);
394                 if (t2p->datap)
395                         free(t2p->datap);
396         }
397     free(t2p);
398 }
399
400 /* called with a VC, an input packet to respond to, and an error code.
401  * sends an error response.
402  */
403 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
404         smb_packet_t *tp, long code)
405 {
406     smb_t *smbp;
407     unsigned short errCode;
408     unsigned char errClass;
409         unsigned long NTStatus;
410
411     if (vcp->flags & SMB_VCFLAG_STATUS32)
412                 smb_MapNTError(code, &NTStatus);
413         else
414                 smb_MapCoreError(code, vcp, &errCode, &errClass);
415
416     smb_FormatResponsePacket(vcp, NULL, tp);
417     smbp = (smb_t *) tp;
418
419         /* We can handle long names */
420         if (vcp->flags & SMB_VCFLAG_USENT)
421                 smbp->flg2 |= 0x40;     /* IS_LONG_NAME */
422         
423     /* now copy important fields from the tran 2 packet */
424     smbp->com = 0x32;           /* tran 2 response */
425     smbp->tid = t2p->tid;
426     smbp->mid = t2p->mid;
427     smbp->pid = t2p->pid;
428     smbp->uid = t2p->uid;
429         smbp->res[0] = t2p->res[0];
430         if (vcp->flags & SMB_VCFLAG_STATUS32) {
431                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
432                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
433                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
434                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
435                 smbp->flg2 |= 0x4000;
436         }
437         else {
438         smbp->rcls = errClass;
439                 smbp->errLow = (unsigned char) (errCode & 0xff);
440                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
441         }
442         
443     /* send packet */
444     smb_SendPacket(vcp, tp);
445 }        
446
447 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
448 {
449     smb_t *smbp;
450     unsigned short parmOffset;
451         unsigned short dataOffset;
452         unsigned short totalLength;
453         unsigned short dataAlign;
454     char *datap;
455         
456     smb_FormatResponsePacket(vcp, NULL, tp);
457     smbp = (smb_t *) tp;
458
459         /* We can handle long names */
460         if (vcp->flags & SMB_VCFLAG_USENT)
461                 smbp->flg2 |= 0x40;     /* IS_LONG_NAME */
462
463     /* now copy important fields from the tran 2 packet */
464     smbp->com = 0x32;           /* tran 2 response */
465     smbp->tid = t2p->tid;
466     smbp->mid = t2p->mid;
467     smbp->pid = t2p->pid;
468     smbp->uid = t2p->uid;
469         smbp->res[0] = t2p->res[0];
470
471     totalLength = 1 + t2p->totalData + t2p->totalParms;
472
473     /* now add the core parameters (tran2 info) to the packet */
474     smb_SetSMBParm(tp, 0, t2p->totalParms);     /* parm bytes */
475     smb_SetSMBParm(tp, 1, t2p->totalData);      /* data bytes */
476     smb_SetSMBParm(tp, 2, 0);           /* reserved */
477     smb_SetSMBParm(tp, 3, t2p->totalParms);     /* parm bytes in this packet */
478         parmOffset = 10*2 + 35;                 /* parm offset in packet */
479         parmOffset++;                           /* round to even */
480     smb_SetSMBParm(tp, 4, parmOffset);  /* 11 parm words plus *
481     * hdr, bcc and wct */
482     smb_SetSMBParm(tp, 5, 0);           /* parm displacement */
483     smb_SetSMBParm(tp, 6, t2p->totalData);      /* data in this packet */
484         dataOffset = parmOffset + t2p->oldTotalParms;
485         dataAlign = dataOffset & 2;             /* quad-align */
486         dataOffset += dataAlign;
487     smb_SetSMBParm(tp, 7, dataOffset);  /* offset of data */
488     smb_SetSMBParm(tp, 8, 0);           /* data displacement */
489     smb_SetSMBParm(tp, 9, 0);           /* low: setup word count *
490     * high: resvd */
491
492     datap = smb_GetSMBData(tp, NULL);
493         *datap++ = 0;                           /* we rounded to even */
494
495         totalLength += dataAlign;
496     smb_SetSMBDataLength(tp, totalLength);
497         
498     /* next, send the datagram */
499     smb_SendPacket(vcp, tp);
500 }   
501
502 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
503 {
504     smb_tran2Packet_t *asp;
505     int totalParms;
506     int totalData;
507     int parmDisp;
508     int dataDisp;
509     int parmOffset;
510     int dataOffset;
511     int parmCount;
512     int dataCount;
513     int firstPacket;
514     long code = 0;
515
516         /* We sometimes see 0 word count.  What to do? */
517         if (*inp->wctp == 0) {
518 #ifndef DJGPP
519                 HANDLE h;
520                 char *ptbuf[1];
521
522                 osi_Log0(smb_logp, "TRANSACTION2 word count = 0"); 
523
524                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
525                 ptbuf[0] = "Transaction2 word count = 0";
526                 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
527                             1, inp->ncb_length, ptbuf, inp);
528                 DeregisterEventSource(h);
529 #else /* DJGPP */
530                 osi_Log0(smb_logp, "TRANSACTION2 word count = 0"); 
531 #endif /* !DJGPP */
532
533         smb_SetSMBDataLength(outp, 0);
534         smb_SendPacket(vcp, outp);
535                 return 0;
536         }
537
538     totalParms = smb_GetSMBParm(inp, 0);
539     totalData = smb_GetSMBParm(inp, 1);
540         
541     firstPacket = (inp->inCom == 0x32);
542         
543         /* find the packet we're reassembling */
544         lock_ObtainWrite(&smb_globalLock);
545     asp = smb_FindTran2Packet(vcp, inp);
546     if (!asp) {
547         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
548         }
549     lock_ReleaseWrite(&smb_globalLock);
550         
551     /* now merge in this latest packet; start by looking up offsets */
552         if (firstPacket) {
553                 parmDisp = dataDisp = 0;
554         parmOffset = smb_GetSMBParm(inp, 10);
555         dataOffset = smb_GetSMBParm(inp, 12);
556         parmCount = smb_GetSMBParm(inp, 9);
557         dataCount = smb_GetSMBParm(inp, 11);
558                 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
559         asp->maxReturnData = smb_GetSMBParm(inp, 3);
560
561                 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
562                  totalData, dataCount, asp->maxReturnData);
563     }
564     else {
565         parmDisp = smb_GetSMBParm(inp, 4);
566         parmOffset = smb_GetSMBParm(inp, 3);
567         dataDisp = smb_GetSMBParm(inp, 7);
568         dataOffset = smb_GetSMBParm(inp, 6);
569         parmCount = smb_GetSMBParm(inp, 2);
570         dataCount = smb_GetSMBParm(inp, 5);
571
572         osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
573                  parmCount, dataCount);
574     }   
575
576     /* now copy the parms and data */
577     if ( parmCount != 0 )
578     {
579         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
580     }
581     if ( dataCount != 0 ) {
582         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
583     }
584
585     /* account for new bytes */
586     asp->curData += dataCount;
587     asp->curParms += parmCount;
588
589     /* finally, if we're done, remove the packet from the queue and dispatch it */
590     if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
591                 /* we've received it all */
592         lock_ObtainWrite(&smb_globalLock);
593                 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
594         lock_ReleaseWrite(&smb_globalLock);
595
596         /* now dispatch it */
597         if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
598             osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
599             osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
600             code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
601         }
602         else {
603             osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
604             osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
605             code = CM_ERROR_BADOP;
606         }
607
608                 /* if an error is returned, we're supposed to send an error packet,
609          * otherwise the dispatched function already did the data sending.
610          * We give dispatched proc the responsibility since it knows how much
611          * space to allocate.
612          */
613         if (code != 0) {
614             smb_SendTran2Error(vcp, asp, outp, code);
615         }
616
617                 /* free the input tran 2 packet */
618                 lock_ObtainWrite(&smb_globalLock);
619         smb_FreeTran2Packet(asp);
620                 lock_ReleaseWrite(&smb_globalLock);
621     }
622     else if (firstPacket) {
623                 /* the first packet in a multi-packet request, we need to send an
624          * ack to get more data.
625          */
626         smb_SetSMBDataLength(outp, 0);
627         smb_SendPacket(vcp, outp);
628     }
629
630         return 0;
631 }
632
633 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
634 {
635         char *pathp;
636     smb_tran2Packet_t *outp;
637     long code = 0;
638         cm_space_t *spacep;
639     int excl;
640     cm_user_t *userp;
641     cm_scache_t *dscp;          /* dir we're dealing with */
642     cm_scache_t *scp;           /* file we're creating */
643     cm_attr_t setAttr;
644     int initialModeBits;
645     smb_fid_t *fidp;
646     int attributes;
647     char *lastNamep;
648     long dosTime;
649     int openFun;
650     int trunc;
651     int openMode;
652     int extraInfo;
653     int openAction;
654     int parmSlot;                       /* which parm we're dealing with */
655     long returnEALength;
656         char *tidPathp;
657         cm_req_t req;
658
659         cm_InitReq(&req);
660
661     scp = NULL;
662         
663         extraInfo = (p->parmsp[0] & 1); /* return extra info */
664     returnEALength = (p->parmsp[0] & 8);        /* return extended attr length */
665
666         openFun = p->parmsp[6];         /* open function */
667     excl = ((openFun & 3) == 0);
668     trunc = ((openFun & 3) == 2);       /* truncate it */
669         openMode = (p->parmsp[1] & 0x7);
670     openAction = 0;                     /* tracks what we did */
671
672     attributes = p->parmsp[3];
673     dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
674         
675         /* compute initial mode bits based on read-only flag in attributes */
676     initialModeBits = 0666;
677     if (attributes & 1) initialModeBits &= ~0222;
678         
679     pathp = (char *) (&p->parmsp[14]);
680         
681     outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
682
683         spacep = cm_GetSpace();
684     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
685
686         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
687                 /* special case magic file name for receiving IOCTL requests
688          * (since IOCTL calls themselves aren't getting through).
689          */
690         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
691         smb_SetupIoctlFid(fidp, spacep);
692
693         /* copy out remainder of the parms */
694                 parmSlot = 0;
695                 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
696                 if (extraInfo) {
697             outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
698             outp->parmsp[parmSlot] = 0; parmSlot++;     /* mod time */
699             outp->parmsp[parmSlot] = 0; parmSlot++;
700             outp->parmsp[parmSlot] = 0; parmSlot++;     /* len */
701             outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
702             outp->parmsp[parmSlot] = openMode; parmSlot++;
703             outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
704             outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
705                 }   
706                 /* and the final "always present" stuff */
707         outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
708                 /* next write out the "unique" ID */
709                 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
710                 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
711         outp->parmsp[parmSlot] = 0; parmSlot++;
712                 if (returnEALength) {
713                         outp->parmsp[parmSlot] = 0; parmSlot++;
714                         outp->parmsp[parmSlot] = 0; parmSlot++;
715         }
716                 
717         outp->totalData = 0;
718         outp->totalParms = parmSlot * 2;
719                 
720         smb_SendTran2Packet(vcp, outp, op);
721                 
722         smb_FreeTran2Packet(outp);
723
724                 /* and clean up fid reference */
725         smb_ReleaseFID(fidp);
726         return 0;
727     }
728
729 #ifdef DEBUG_VERBOSE
730         {
731                 char *hexp, *asciip;
732                 asciip = (lastNamep ? lastNamep : pathp);
733                 hexp = osi_HexifyString( asciip );
734                 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
735                 free(hexp);
736         }
737 #endif
738
739         userp = smb_GetTran2User(vcp, p);
740     /* In the off chance that userp is NULL, we log and abandon */
741     if(!userp) {
742         osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
743         smb_FreeTran2Packet(outp);
744         return CM_ERROR_BADSMB;
745     }
746
747         tidPathp = smb_GetTIDPath(vcp, p->tid);
748
749         dscp = NULL;
750         code = cm_NameI(cm_rootSCachep, pathp,
751                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
752                     userp, tidPathp, &req, &scp);
753         if (code != 0) {
754                 code = cm_NameI(cm_rootSCachep, spacep->data,
755                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
756                         userp, tidPathp, &req, &dscp);
757                 cm_FreeSpace(spacep);
758
759         if (code) {
760             cm_ReleaseUser(userp);
761                         smb_FreeTran2Packet(outp);
762             return code;
763         }
764         
765         /* otherwise, scp points to the parent directory.  Do a lookup,
766                  * and truncate the file if we find it, otherwise we create the
767                  * file.
768          */
769         if (!lastNamep) lastNamep = pathp;
770         else lastNamep++;
771         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
772                          &req, &scp);
773         if (code && code != CM_ERROR_NOSUCHFILE) {
774                         cm_ReleaseSCache(dscp);
775             cm_ReleaseUser(userp);
776                         smb_FreeTran2Packet(outp);
777             return code;
778         }
779         }
780     else {
781         cm_FreeSpace(spacep);
782         }
783         
784     /* if we get here, if code is 0, the file exists and is represented by
785      * scp.  Otherwise, we have to create it.
786      */
787         if (code == 0) {
788         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
789         if (code) {
790             if (dscp) cm_ReleaseSCache(dscp);
791             cm_ReleaseSCache(scp);
792             cm_ReleaseUser(userp);
793                         smb_FreeTran2Packet(outp);
794             return code;
795         }
796
797                 if (excl) {
798                         /* oops, file shouldn't be there */
799             if (dscp) cm_ReleaseSCache(dscp);
800             cm_ReleaseSCache(scp);
801             cm_ReleaseUser(userp);
802                         smb_FreeTran2Packet(outp);
803             return CM_ERROR_EXISTS;
804         }
805
806                 if (trunc) {
807                         setAttr.mask = CM_ATTRMASK_LENGTH;
808             setAttr.length.LowPart = 0;
809             setAttr.length.HighPart = 0;
810                         code = cm_SetAttr(scp, &setAttr, userp, &req);
811             openAction = 3;     /* truncated existing file */
812                 }   
813         else openAction = 1;    /* found existing file */
814     }
815         else if (!(openFun & SMB_ATTR_DIRECTORY)) {
816                 /* don't create if not found */
817         if (dscp) cm_ReleaseSCache(dscp);
818         osi_assert(scp == NULL);
819         cm_ReleaseUser(userp);
820                 smb_FreeTran2Packet(outp);
821         return CM_ERROR_NOSUCHFILE;
822     }
823     else {
824                 osi_assert(dscp != NULL && scp == NULL);
825                 openAction = 2; /* created file */
826                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
827                 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
828         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
829                          &req);
830                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
831                         smb_NotifyChange(FILE_ACTION_ADDED,
832                              FILE_NOTIFY_CHANGE_FILE_NAME,  
833                              dscp, lastNamep, NULL, TRUE);
834         if (!excl && code == CM_ERROR_EXISTS) {
835                         /* not an exclusive create, and someone else tried
836                          * creating it already, then we open it anyway.  We
837                          * don't bother retrying after this, since if this next
838                          * fails, that means that the file was deleted after we
839                          * started this call.
840              */
841             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
842                              userp, &req, &scp);
843             if (code == 0) {
844                 if (trunc) {
845                                         setAttr.mask = CM_ATTRMASK_LENGTH;
846                     setAttr.length.LowPart = 0;
847                     setAttr.length.HighPart = 0;
848                     code = cm_SetAttr(scp, &setAttr, userp,
849                                       &req);
850                 }   
851                         }       /* lookup succeeded */
852         }
853     }
854         
855         /* we don't need this any longer */
856         if (dscp) cm_ReleaseSCache(dscp);
857
858     if (code) {
859                 /* something went wrong creating or truncating the file */
860         if (scp) cm_ReleaseSCache(scp);
861         cm_ReleaseUser(userp);
862                 smb_FreeTran2Packet(outp);
863         return code;
864     }
865         
866         /* make sure we're about to open a file */
867         if (scp->fileType != CM_SCACHETYPE_FILE) {
868                 cm_ReleaseSCache(scp);
869                 cm_ReleaseUser(userp);
870                 smb_FreeTran2Packet(outp);
871                 return CM_ERROR_ISDIR;
872         }
873
874     /* now all we have to do is open the file itself */
875     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
876     osi_assert(fidp);
877         
878         /* save a pointer to the vnode */
879     fidp->scp = scp;
880         
881         /* compute open mode */
882     if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
883     if (openMode == 1 || openMode == 2)
884         fidp->flags |= SMB_FID_OPENWRITE;
885
886         smb_ReleaseFID(fidp);
887         
888         cm_Open(scp, 0, userp);
889
890     /* copy out remainder of the parms */
891         parmSlot = 0;
892         outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
893         lock_ObtainMutex(&scp->mx);
894         if (extraInfo) {
895         outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
896                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
897         outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
898         outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
899         outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
900         parmSlot++;
901         outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
902         parmSlot++;
903         outp->parmsp[parmSlot] = openMode; parmSlot++;
904         outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
905         outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
906         }   
907         /* and the final "always present" stuff */
908     outp->parmsp[parmSlot] = openAction; parmSlot++;
909         /* next write out the "unique" ID */
910         outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
911         outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
912     outp->parmsp[parmSlot] = 0; parmSlot++;
913     if (returnEALength) {
914                 outp->parmsp[parmSlot] = 0; parmSlot++;
915                 outp->parmsp[parmSlot] = 0; parmSlot++;
916     }
917         lock_ReleaseMutex(&scp->mx);
918         outp->totalData = 0;            /* total # of data bytes */
919     outp->totalParms = parmSlot * 2;    /* shorts are two bytes */
920
921         smb_SendTran2Packet(vcp, outp, op);
922         
923     smb_FreeTran2Packet(outp);
924
925     cm_ReleaseUser(userp);
926     /* leave scp held since we put it in fidp->scp */
927     return 0;
928 }   
929
930 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
931 {
932     return CM_ERROR_BADOP;
933 }
934
935 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
936 {
937     return CM_ERROR_BADOP;
938 }
939
940 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
941 {
942         smb_tran2Packet_t *outp;
943     smb_tran2QFSInfo_t qi;
944         int responseSize;
945         osi_hyper_t temp;
946         static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
947         
948         osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
949
950         switch (p->parmsp[0]) {
951         case 1: responseSize = sizeof(qi.u.allocInfo); break;
952         case 2: responseSize = sizeof(qi.u.volumeInfo); break;
953         case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
954         case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
955         case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
956         case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
957         default: return CM_ERROR_INVAL;
958         }
959
960     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
961         switch (p->parmsp[0]) {
962         case 1:
963                 /* alloc info */
964         qi.u.allocInfo.FSID = 0;
965         qi.u.allocInfo.sectorsPerAllocUnit = 1;
966         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
967         qi.u.allocInfo.availAllocUnits = 0x3fffffff;
968         qi.u.allocInfo.bytesPerSector = 1024;
969                 break;
970
971     case 2:
972                 /* volume info */
973         qi.u.volumeInfo.vsn = 1234;
974         qi.u.volumeInfo.vnCount = 4;
975                 /* we're supposed to pad it out with zeroes to the end */
976                 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
977         memcpy(qi.u.volumeInfo.label, "AFS", 4);
978                 break;
979
980         case 0x102:
981                 /* FS volume info */
982                 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
983                 qi.u.FSvolumeInfo.vsn = 1234;
984                 qi.u.FSvolumeInfo.vnCount = 8;
985                 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
986                 break;
987
988         case 0x103:
989                 /* FS size info */
990                 temp.HighPart = 0;
991                 temp.LowPart = 0x7fffffff;
992                 qi.u.FSsizeInfo.totalAllocUnits = temp;
993                 temp.LowPart = 0x3fffffff;
994                 qi.u.FSsizeInfo.availAllocUnits = temp;
995                 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
996                 qi.u.FSsizeInfo.bytesPerSector = 1024;
997                 break;
998
999         case 0x104:
1000                 /* FS device info */
1001                 qi.u.FSdeviceInfo.devType = 0;  /* don't have a number */
1002                 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
1003                 break;
1004
1005         case 0x105:
1006                 /* FS attribute info */
1007                 /* attributes, defined in WINNT.H:
1008                  *      FILE_CASE_SENSITIVE_SEARCH      0x1
1009                  *      FILE_CASE_PRESERVED_NAMES       0x2
1010                  *      <no name defined>               0x4000
1011                  *         If bit 0x4000 is not set, Windows 95 thinks
1012                  *         we can't handle long (non-8.3) names,
1013                  *         despite our protestations to the contrary.
1014                  */
1015                 qi.u.FSattributeInfo.attributes = 0x4003;
1016                 qi.u.FSattributeInfo.maxCompLength = 255;
1017                 qi.u.FSattributeInfo.FSnameLength = 6;
1018                 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
1019                 break;
1020     }
1021         
1022         /* copy out return data, and set corresponding sizes */
1023         outp->totalParms = 0;
1024     outp->totalData = responseSize;
1025     memcpy(outp->datap, &qi, responseSize);
1026
1027         /* send and free the packets */
1028         smb_SendTran2Packet(vcp, outp, op);
1029     smb_FreeTran2Packet(outp);
1030
1031     return 0;
1032 }
1033
1034 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1035 {
1036     return CM_ERROR_BADOP;
1037 }
1038
1039 struct smb_ShortNameRock {
1040         char *maskp;
1041         unsigned int vnode;
1042         char *shortName;
1043         size_t shortNameLen;
1044 };
1045
1046 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
1047         osi_hyper_t *offp)
1048 {
1049         struct smb_ShortNameRock *rockp;
1050         char *shortNameEnd;
1051
1052         rockp = vrockp;
1053         /* compare both names and vnodes, though probably just comparing vnodes
1054          * would be safe enough.
1055          */
1056         if (cm_stricmp(dep->name, rockp->maskp) != 0)
1057                 return 0;
1058         if (ntohl(dep->fid.vnode) != rockp->vnode)
1059                 return 0;
1060         /* This is the entry */
1061         cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1062         rockp->shortNameLen = shortNameEnd - rockp->shortName;
1063         return CM_ERROR_STOPNOW;
1064 }
1065
1066 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1067         char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1068 {
1069         struct smb_ShortNameRock rock;
1070         char *lastNamep;
1071         cm_space_t *spacep;
1072         cm_scache_t *dscp;
1073         int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1074         long code = 0;
1075         osi_hyper_t thyper;
1076
1077         spacep = cm_GetSpace();
1078         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1079
1080         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1081                      reqp, &dscp);
1082         cm_FreeSpace(spacep);
1083         if (code) return code;
1084
1085         if (!lastNamep) lastNamep = pathp;
1086         else lastNamep++;
1087         thyper.LowPart = 0;
1088         thyper.HighPart = 0;
1089         rock.shortName = shortName;
1090         rock.vnode = vnode;
1091         rock.maskp = lastNamep;
1092         code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1093                         reqp, NULL);
1094
1095         cm_ReleaseSCache(dscp);
1096
1097         if (code == 0)
1098                 return CM_ERROR_NOSUCHFILE;
1099         if (code == CM_ERROR_STOPNOW) {
1100                 *shortNameLenp = rock.shortNameLen;
1101                 return 0;
1102         }
1103         return code;
1104 }
1105
1106 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1107 {
1108         smb_tran2Packet_t *outp;
1109     unsigned long dosTime;
1110         FILETIME ft;
1111     unsigned short infoLevel;
1112     int nbytesRequired;
1113     unsigned short attributes;
1114         unsigned long extAttributes;
1115         char shortName[13];
1116         unsigned int len;
1117     cm_user_t *userp;
1118         cm_space_t *spacep;
1119     cm_scache_t *scp, *dscp;
1120     long code = 0;
1121     char *op;
1122         char *tidPathp;
1123         char *lastComp;
1124         cm_req_t req;
1125
1126         cm_InitReq(&req);
1127
1128         infoLevel = p->parmsp[0];
1129     if (infoLevel == 6) nbytesRequired = 0;
1130     else if (infoLevel == 1) nbytesRequired = 22;
1131     else if (infoLevel == 2) nbytesRequired = 26;
1132         else if (infoLevel == 0x101) nbytesRequired = 40;
1133         else if (infoLevel == 0x102) nbytesRequired = 24;
1134         else if (infoLevel == 0x103) nbytesRequired = 4;
1135         else if (infoLevel == 0x108) nbytesRequired = 30;
1136     else {
1137                 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1138                   p->opcode, infoLevel);
1139                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1140         return 0;
1141     }
1142         osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1143              osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
1144
1145     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1146
1147         if (infoLevel > 0x100)
1148                 outp->totalParms = 2;
1149         else
1150                 outp->totalParms = 0;
1151         outp->totalData = nbytesRequired;
1152         
1153     /* now, if we're at infoLevel 6, we're only being asked to check
1154      * the syntax, so we just OK things now.  In particular, we're *not*
1155      * being asked to verify anything about the state of any parent dirs.
1156      */
1157         if (infoLevel == 6) {
1158                 smb_SendTran2Packet(vcp, outp, opx);
1159         smb_FreeTran2Packet(outp);
1160                 return 0;
1161     }
1162         
1163     userp = smb_GetTran2User(vcp, p);
1164     if(!userp) {
1165         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
1166         smb_FreeTran2Packet(outp);
1167         return CM_ERROR_BADSMB;
1168     }
1169
1170         tidPathp = smb_GetTIDPath(vcp, p->tid);
1171
1172         /*
1173          * XXX Strange hack XXX
1174          *
1175          * As of Patch 7 (13 January 98), we are having the following problem:
1176          * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1177          * requests to look up "desktop.ini" in all the subdirectories.
1178          * This can cause zillions of timeouts looking up non-existent cells
1179          * and volumes, especially in the top-level directory.
1180          *
1181          * We have not found any way to avoid this or work around it except
1182          * to explicitly ignore the requests for mount points that haven't
1183          * yet been evaluated and for directories that haven't yet been
1184          * fetched.
1185          */
1186         if (infoLevel == 0x101) {
1187                 spacep = cm_GetSpace();
1188                 smb_StripLastComponent(spacep->data, &lastComp,
1189                                         (char *)(&p->parmsp[3]));
1190                 /* Make sure that lastComp is not NULL */
1191                 if (lastComp) {
1192                     if (strcmp(lastComp, "\\desktop.ini") == 0) {
1193                 code = cm_NameI(cm_rootSCachep, spacep->data,
1194                                 CM_FLAG_CASEFOLD
1195                                 | CM_FLAG_DIRSEARCH
1196                                 | CM_FLAG_FOLLOW,
1197                                 userp, tidPathp, &req, &dscp);
1198                 if (code == 0) {
1199                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1200                          && !dscp->mountRootFidp)
1201                         code = CM_ERROR_NOSUCHFILE;
1202                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1203                         cm_buf_t *bp = buf_Find(dscp, &hzero);
1204                         if (bp)
1205                             buf_Release(bp);
1206                         else
1207                             code = CM_ERROR_NOSUCHFILE;
1208                     }
1209                     cm_ReleaseSCache(dscp);
1210                     if (code) {
1211                         cm_FreeSpace(spacep);
1212                         cm_ReleaseUser(userp);
1213                         smb_SendTran2Error(vcp, p, opx, code);
1214                         smb_FreeTran2Packet(outp);
1215                         return 0;
1216                     }
1217                 }
1218             }
1219         }
1220                 cm_FreeSpace(spacep);
1221         }
1222
1223         /* now do namei and stat, and copy out the info */
1224     code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1225                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1226
1227         if (code) {
1228                 cm_ReleaseUser(userp);
1229         smb_SendTran2Error(vcp, p, opx, code);
1230         smb_FreeTran2Packet(outp);
1231         return 0;
1232     }
1233
1234     lock_ObtainMutex(&scp->mx);
1235         code = cm_SyncOp(scp, NULL, userp, &req, 0,
1236                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1237         if (code) goto done;
1238         
1239     /* now we have the status in the cache entry, and everything is locked.
1240          * Marshall the output data.
1241      */
1242         op = outp->datap;
1243         /* for info level 108, figure out short name */
1244         if (infoLevel == 0x108) {
1245                 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1246                                 tidPathp, scp->fid.vnode, shortName,
1247                                 (size_t *) &len);
1248                 if (code) {
1249                         goto done;
1250                 }
1251
1252                 op = outp->datap;
1253                 *((u_long *)op) = len * 2; op += 4;
1254                 mbstowcs((unsigned short *)op, shortName, len);
1255                 op += (len * 2);
1256
1257                 goto done;
1258         }
1259         if (infoLevel == 1 || infoLevel == 2) {
1260                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1261         *((u_long *)op) = dosTime; op += 4;     /* creation time */
1262         *((u_long *)op) = dosTime; op += 4;     /* access time */
1263         *((u_long *)op) = dosTime; op += 4;     /* write time */
1264         *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1265         *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1266                 attributes = smb_Attributes(scp);
1267                 *((u_short *)op) = attributes; op += 2; /* attributes */
1268         }
1269         else if (infoLevel == 0x101) {
1270                 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1271                 *((FILETIME *)op) = ft; op += 8;        /* creation time */
1272                 *((FILETIME *)op) = ft; op += 8;        /* last access time */
1273                 *((FILETIME *)op) = ft; op += 8;        /* last write time */
1274                 *((FILETIME *)op) = ft; op += 8;        /* last change time */
1275                 extAttributes = smb_ExtAttributes(scp);
1276                 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1277                 *((u_long *)op) = 0; op += 4;   /* don't know what this is */
1278         }
1279         else if (infoLevel == 0x102) {
1280                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
1281                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
1282                 *((u_long *)op) = scp->linkCount; op += 4;
1283                 *op++ = 0;
1284                 *op++ = 0;
1285                 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1286                 *op++ = 0;
1287         }
1288         else if (infoLevel == 0x103) {
1289                 memset(op, 0, 4); op += 4;      /* EA size */
1290         }
1291
1292         /* now, if we are being asked about extended attrs, return a 0 size */
1293         if (infoLevel == 2) {
1294                 *((u_long *)op) = 0; op += 4;
1295         }
1296         
1297
1298         /* send and free the packets */
1299   done:
1300         lock_ReleaseMutex(&scp->mx);
1301     cm_ReleaseSCache(scp);
1302     cm_ReleaseUser(userp);
1303         if (code == 0) 
1304         smb_SendTran2Packet(vcp, outp, opx);
1305     else 
1306         smb_SendTran2Error(vcp, p, opx, code);
1307     smb_FreeTran2Packet(outp);
1308
1309     return 0;
1310 }
1311
1312 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1313 {
1314     return CM_ERROR_BADOP;
1315 }
1316
1317 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1318 {
1319         smb_tran2Packet_t *outp;
1320         FILETIME ft;
1321         unsigned long attributes;
1322         unsigned short infoLevel;
1323         int nbytesRequired;
1324         unsigned short fid;
1325         cm_user_t *userp;
1326     smb_fid_t *fidp;
1327         cm_scache_t *scp;
1328         char *op;
1329         long code = 0;
1330         cm_req_t req;
1331
1332         cm_InitReq(&req);
1333
1334     fid = p->parmsp[0];
1335     fidp = smb_FindFID(vcp, fid, 0);
1336
1337         if (fidp == NULL) {
1338                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
1339                 return 0;
1340         }
1341
1342         infoLevel = p->parmsp[1];
1343         if (infoLevel == 0x101) nbytesRequired = 40;
1344         else if (infoLevel == 0x102) nbytesRequired = 24;
1345         else if (infoLevel == 0x103) nbytesRequired = 4;
1346         else if (infoLevel == 0x104) nbytesRequired = 6;
1347         else {
1348                 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1349                  p->opcode, infoLevel);
1350                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1351         smb_ReleaseFID(fidp);
1352                 return 0;
1353         }
1354         osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1355
1356         outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1357
1358         if (infoLevel > 0x100)
1359                 outp->totalParms = 2;
1360         else
1361                 outp->totalParms = 0;
1362         outp->totalData = nbytesRequired;
1363
1364         userp = smb_GetTran2User(vcp, p);
1365     if(!userp) {
1366         osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
1367         code = CM_ERROR_BADSMB;
1368         goto done;
1369     }
1370
1371         scp = fidp->scp;
1372         lock_ObtainMutex(&scp->mx);
1373         code = cm_SyncOp(scp, NULL, userp, &req, 0,
1374                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1375         if (code) goto done;
1376
1377         /* now we have the status in the cache entry, and everything is locked.
1378          * Marshall the output data.
1379          */
1380         op = outp->datap;
1381         if (infoLevel == 0x101) {
1382                 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1383                 *((FILETIME *)op) = ft; op += 8;        /* creation time */
1384                 *((FILETIME *)op) = ft; op += 8;        /* last access time */
1385                 *((FILETIME *)op) = ft; op += 8;        /* last write time */
1386                 *((FILETIME *)op) = ft; op += 8;        /* last change time */
1387                 attributes = smb_ExtAttributes(scp);
1388                 *((u_long *)op) = attributes; op += 4;
1389                 *((u_long *)op) = 0; op += 4;
1390         }
1391         else if (infoLevel == 0x102) {
1392                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
1393                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
1394                 *((u_long *)op) = scp->linkCount; op += 4;
1395                 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1396                 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1397                 *op++ = 0;
1398                 *op++ = 0;
1399         }
1400         else if (infoLevel == 0x103) {
1401                 *((u_long *)op) = 0; op += 4;
1402         }
1403         else if (infoLevel == 0x104) {
1404                 unsigned long len;
1405                 char *name;
1406
1407                 if (fidp->NTopen_wholepathp)
1408                         name = fidp->NTopen_wholepathp;
1409                 else
1410                         name = "\\";    /* probably can't happen */
1411                 len = strlen(name);
1412                 outp->totalData = (len*2) + 4;  /* this is actually what we want to return */
1413                 *((u_long *)op) = len * 2; op += 4;
1414                 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1415         }
1416
1417         /* send and free the packets */
1418   done:
1419         lock_ReleaseMutex(&scp->mx);
1420         cm_ReleaseUser(userp);
1421         smb_ReleaseFID(fidp);
1422         if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1423         else smb_SendTran2Error(vcp, p, opx, code);
1424         smb_FreeTran2Packet(outp);
1425
1426         return 0;
1427 }
1428
1429 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1430 {
1431         long code = 0;
1432         unsigned short fid;
1433         smb_fid_t *fidp;
1434         unsigned short infoLevel;
1435         smb_tran2Packet_t *outp;
1436         cm_user_t *userp;
1437         cm_scache_t *scp;
1438         cm_req_t req;
1439
1440         cm_InitReq(&req);
1441
1442     fid = p->parmsp[0];
1443         fidp = smb_FindFID(vcp, fid, 0);
1444
1445         if (fidp == NULL) {
1446                 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1447                 return 0;
1448         }
1449
1450         infoLevel = p->parmsp[1];
1451         if (infoLevel > 0x104 || infoLevel < 0x101) {
1452                 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1453                          p->opcode, infoLevel);
1454                 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1455         smb_ReleaseFID(fidp);
1456                 return 0;
1457         }
1458
1459         if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1460                 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1461         smb_ReleaseFID(fidp);
1462                 return 0;
1463         }
1464         if ((infoLevel == 0x103 || infoLevel == 0x104)
1465             && !(fidp->flags & SMB_FID_OPENWRITE)) {
1466                 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1467         smb_ReleaseFID(fidp);
1468                 return 0;
1469         }
1470
1471         osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
1472
1473         outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1474
1475         outp->totalParms = 2;
1476         outp->totalData = 0;
1477
1478         userp = smb_GetTran2User(vcp, p);
1479     if(!userp) {
1480         osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
1481         code = CM_ERROR_BADSMB;
1482         goto done;
1483     }
1484
1485         scp = fidp->scp;
1486
1487         if (infoLevel == 0x101) {
1488                 FILETIME lastMod;
1489                 unsigned int attribute;
1490                 cm_attr_t attr;
1491
1492                 /* lock the vnode with a callback; we need the current status
1493                  * to determine what the new status is, in some cases.
1494                  */
1495                 lock_ObtainMutex(&scp->mx);
1496                 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1497                          CM_SCACHESYNC_GETSTATUS
1498                          | CM_SCACHESYNC_NEEDCALLBACK);
1499                 if (code) {
1500                         lock_ReleaseMutex(&scp->mx);
1501                         goto done;
1502                 }
1503
1504                 /* prepare for setattr call */
1505                 attr.mask = 0;
1506                 
1507                 lastMod = *((FILETIME *)(p->datap + 16));
1508                 /* when called as result of move a b, lastMod is (-1, -1). 
1509          * If the check for -1 is not present, timestamp
1510                  * of the resulting file will be 1969 (-1)
1511                  */
1512                 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && 
1513             lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
1514                         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1515                         smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1516                                                         &lastMod);
1517                         fidp->flags |= SMB_FID_MTIMESETDONE;
1518                 }
1519                 
1520                 attribute = *((u_long *)(p->datap + 32));
1521                 if (attribute != 0) {
1522                         if ((scp->unixModeBits & 0222)
1523                             && (attribute & 1) != 0) {
1524                                 /* make a writable file read-only */
1525                                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1526                                 attr.unixModeBits = scp->unixModeBits & ~0222;
1527                         }
1528                         else if ((scp->unixModeBits & 0222) == 0
1529                                  && (attribute & 1) == 0) {
1530                                 /* make a read-only file writable */
1531                                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1532                                 attr.unixModeBits = scp->unixModeBits | 0222;
1533                         }
1534                 }
1535                 lock_ReleaseMutex(&scp->mx);
1536
1537                 /* call setattr */
1538                 if (attr.mask)
1539                         code = cm_SetAttr(scp, &attr, userp, &req);
1540                 else
1541                         code = 0;
1542         }
1543         else if (infoLevel == 0x103 || infoLevel == 0x104) {
1544                 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1545                 cm_attr_t attr;
1546
1547                 attr.mask = CM_ATTRMASK_LENGTH;
1548                 attr.length.LowPart = size.LowPart;
1549                 attr.length.HighPart = size.HighPart;
1550                 code = cm_SetAttr(scp, &attr, userp, &req);
1551         }
1552         else if (infoLevel == 0x102) {
1553                 if (*((char *)(p->datap))) {
1554                         code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1555                                                 &req);
1556                         if (code == 0)
1557                                 fidp->flags |= SMB_FID_DELONCLOSE;
1558                 }
1559                 else {
1560                         code = 0;
1561                         fidp->flags &= ~SMB_FID_DELONCLOSE;
1562                 }
1563         }
1564   done:
1565         cm_ReleaseUser(userp);
1566         smb_ReleaseFID(fidp);
1567         if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1568         else smb_SendTran2Error(vcp, p, op, code);
1569         smb_FreeTran2Packet(outp);
1570
1571         return 0;
1572 }
1573
1574 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1575 {
1576     return CM_ERROR_BADOP;
1577 }
1578
1579 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1580 {
1581     return CM_ERROR_BADOP;
1582 }
1583
1584 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1585 {
1586     return CM_ERROR_BADOP;
1587 }
1588
1589 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1590 {
1591     return CM_ERROR_BADOP;
1592 }
1593
1594 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1595 {
1596     return CM_ERROR_BADOP;
1597 }
1598
1599 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1600         smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1601         cm_req_t *reqp)
1602 {
1603         long code = 0;
1604     cm_scache_t *scp;
1605     cm_scache_t *targetScp;                     /* target if scp is a symlink */
1606     char *dptr;
1607     long dosTime;
1608         FILETIME ft;
1609     int shortTemp;
1610     unsigned short attr;
1611         unsigned long lattr;
1612     smb_dirListPatch_t *patchp;
1613     smb_dirListPatch_t *npatchp;
1614         
1615     for(patchp = *dirPatchespp; patchp; patchp =
1616          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1617                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1618         if (code) continue;
1619         lock_ObtainMutex(&scp->mx);
1620         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1621                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1622                 if (code) { 
1623                         lock_ReleaseMutex(&scp->mx);
1624                         cm_ReleaseSCache(scp);
1625                         continue;
1626         }
1627                 
1628         /* now watch for a symlink */
1629         if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1630                         lock_ReleaseMutex(&scp->mx);
1631             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
1632             if (code == 0) {
1633                                 /* we have a more accurate file to use (the
1634                                  * target of the symbolic link).  Otherwise,
1635                                  * we'll just use the symlink anyway.
1636                  */
1637                                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
1638                          scp, targetScp);
1639                                 cm_ReleaseSCache(scp);
1640                 scp = targetScp;
1641             }
1642             lock_ObtainMutex(&scp->mx);
1643         }
1644
1645                 dptr = patchp->dptr;
1646
1647                 if (infoLevel >= 0x101) {
1648                         /* get filetime */
1649                         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1650
1651                         /* copy to Creation Time */
1652                         *((FILETIME *)dptr) = ft;
1653                         dptr += 8;
1654
1655                         /* copy to Last Access Time */
1656                         *((FILETIME *)dptr) = ft;
1657                         dptr += 8;
1658
1659                         /* copy to Last Write Time */
1660                         *((FILETIME *)dptr) = ft;
1661                         dptr += 8;
1662
1663                         /* copy to Change Time */
1664                         *((FILETIME *)dptr) = ft;
1665                         dptr += 8;
1666
1667                         /* Use length for both file length and alloc length */
1668                         *((LARGE_INTEGER *)dptr) = scp->length;
1669                         dptr += 8;
1670                         *((LARGE_INTEGER *)dptr) = scp->length;
1671                         dptr += 8;
1672
1673                         /* Copy attributes */
1674                         lattr = smb_ExtAttributes(scp);
1675             /* merge in hidden (dot file) attribute */
1676                         if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1677                                 lattr |= SMB_ATTR_HIDDEN;
1678                         *((u_long *)dptr) = lattr;
1679                         dptr += 4;
1680                 }
1681                 else {
1682                         /* get dos time */
1683                         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1684
1685                         /* and copy out date */
1686                         shortTemp = (dosTime>>16) & 0xffff;
1687                         *((u_short *)dptr) = shortTemp;
1688                         dptr += 2;
1689
1690                         /* copy out creation time */
1691                         shortTemp = dosTime & 0xffff;
1692                         *((u_short *)dptr) = shortTemp;
1693                         dptr += 2;
1694
1695                         /* and copy out date */
1696                         shortTemp = (dosTime>>16) & 0xffff;
1697                         *((u_short *)dptr) = shortTemp;
1698                         dptr += 2;
1699                         
1700                         /* copy out access time */
1701                         shortTemp = dosTime & 0xffff;
1702                         *((u_short *)dptr) = shortTemp;
1703                         dptr += 2;
1704
1705                         /* and copy out date */
1706                         shortTemp = (dosTime>>16) & 0xffff;
1707                         *((u_short *)dptr) = shortTemp;
1708                         dptr += 2;
1709                         
1710                         /* copy out mod time */
1711                         shortTemp = dosTime & 0xffff;
1712                         *((u_short *)dptr) = shortTemp;
1713                         dptr += 2;
1714
1715                         /* copy out file length and alloc length,
1716                          * using the same for both
1717                          */
1718                         *((u_long *)dptr) = scp->length.LowPart;
1719                         dptr += 4;
1720                         *((u_long *)dptr) = scp->length.LowPart;
1721                         dptr += 4;
1722
1723                         /* finally copy out attributes as short */
1724                         attr = smb_Attributes(scp);
1725             /* merge in hidden (dot file) attribute */
1726             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1727                 attr |= SMB_ATTR_HIDDEN;
1728                         *dptr++ = attr & 0xff;
1729                         *dptr++ = (attr >> 8) & 0xff;
1730                 }
1731
1732         lock_ReleaseMutex(&scp->mx);
1733         cm_ReleaseSCache(scp);
1734         }
1735         
1736     /* now free the patches */
1737     for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1738                 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1739         free(patchp);
1740         }
1741         
1742     /* and mark the list as empty */
1743     *dirPatchespp = NULL;
1744
1745     return code;
1746 }
1747
1748 /* do a case-folding search of the star name mask with the name in namep.
1749  * Return 1 if we match, otherwise 0.
1750  */
1751 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1752 {
1753         unsigned char tcp1, tcp2;       /* Pattern characters */
1754     unsigned char tcn1;         /* Name characters */
1755         int sawDot = 0, sawStar = 0, req8dot3 = 0;
1756         char *starNamep, *starMaskp;
1757         static char nullCharp[] = {0};
1758     int casefold = flags & CM_FLAG_CASEFOLD;
1759
1760         /* make sure we only match 8.3 names, if requested */
1761     req8dot3 = (flags & CM_FLAG_8DOT3);
1762         if (req8dot3 && !cm_Is8Dot3(namep)) 
1763         return 0;
1764
1765         /* loop */
1766         while (1) {
1767                 /* Next pattern character */
1768                 tcp1 = *maskp++;
1769
1770                 /* Next name character */
1771                 tcn1 = *namep;
1772
1773                 if (tcp1 == 0) {
1774                         /* 0 - end of pattern */
1775                         if (tcn1 == 0)
1776                                 return 1;
1777                         else
1778                                 return 0;
1779                 }
1780                 else if (tcp1 == '.' || tcp1 == '"') {
1781                         if (sawDot) {
1782                                 if (tcn1 == '.') {
1783                                         namep++;
1784                                         continue;
1785                                 } else
1786                                         return 0;
1787                         }
1788                         else {
1789                                 /*
1790                                  * first dot in pattern;
1791                                  * must match dot or end of name
1792                                  */
1793                                 sawDot = 1;
1794                                 if (tcn1 == 0)
1795                                         continue;
1796                                 else if (tcn1 == '.') {
1797                                         sawStar = 0;
1798                                         namep++;
1799                                         continue;
1800                                 }
1801                                 else
1802                                         return 0;
1803                         }
1804                 }
1805                 else if (tcp1 == '?') {
1806                         if (tcn1 == 0 || tcn1 == '.')
1807                                 return 0;
1808                         namep++;
1809                         continue;
1810                 }
1811                 else if (tcp1 == '>') {
1812                         if (tcn1 != 0 && tcn1 != '.')
1813                                 namep++;
1814                         continue;
1815                 }
1816                 else if (tcp1 == '*' || tcp1 == '<') {
1817                         tcp2 = *maskp++;
1818                         if (tcp2 == 0)
1819                                 return 1;
1820                         else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
1821                                 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
1822                                         tcn1 = *++namep;
1823                                 if (tcn1 == 0) {
1824                                         if (sawDot)
1825                                                 return 0;
1826                                         else
1827                                                 continue;
1828                                 }
1829                                 else {
1830                                         namep++;
1831                                         continue;
1832                                 }
1833                         }
1834                         else {
1835                                 /*
1836                                  * pattern character after '*' is not null or
1837                                  * period.  If it is '?' or '>', we are not
1838                                  * going to understand it.  If it is '*' or
1839                                  * '<', we are going to skip over it.  None of
1840                                  * these are likely, I hope.
1841                                  */
1842                                 /* skip over '*' and '<' */
1843                                 while (tcp2 == '*' || tcp2 == '<')
1844                                         tcp2 = *maskp++;
1845
1846                                 /* skip over characters that don't match tcp2 */
1847                                 while (req8dot3 && tcn1 != '.' && tcn1 != 0 && 
1848                        ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) || 
1849                          (!casefold && tcn1 != tcp2)))
1850                                         tcn1 = *++namep;
1851
1852                                 /* No match */
1853                                 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
1854                                         return 0;
1855
1856                                 /* Remember where we are */
1857                                 sawStar = 1;
1858                                 starMaskp = maskp;
1859                                 starNamep = namep;
1860
1861                                 namep++;
1862                                 continue;
1863                         }
1864                 }
1865                 else {
1866                         /* tcp1 is not a wildcard */
1867             if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) || 
1868                 (!casefold && tcn1 == tcp1)) {
1869                                 /* they match */
1870                                 namep++;
1871                                 continue;
1872                         }
1873                         /* if trying to match a star pattern, go back */
1874                         if (sawStar) {
1875                                 maskp = starMaskp - 2;
1876                                 namep = starNamep + 1;
1877                                 sawStar = 0;
1878                                 continue;
1879                         }
1880                         /* that's all */
1881                         return 0;
1882                 }
1883         }
1884 }
1885
1886 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1887 {
1888         int attribute;
1889     long nextCookie;
1890     char *tp;
1891     long code = 0;
1892     char *pathp;
1893     cm_dirEntry_t *dep;
1894     int maxCount;
1895     smb_dirListPatch_t *dirListPatchesp;
1896     smb_dirListPatch_t *curPatchp;
1897     cm_buf_t *bufferp;
1898     long temp;
1899     long orbytes;                       /* # of bytes in this output record */
1900     long ohbytes;                       /* # of bytes, except file name */
1901     long onbytes;                       /* # of bytes in name, incl. term. null */
1902     osi_hyper_t dirLength;
1903     osi_hyper_t bufferOffset;
1904     osi_hyper_t curOffset;
1905     osi_hyper_t thyper;
1906     smb_dirSearch_t *dsp;
1907     cm_scache_t *scp;
1908     long entryInDir;
1909     long entryInBuffer;
1910         cm_pageHeader_t *pageHeaderp;
1911     cm_user_t *userp = NULL;
1912     int slotInPage;
1913     int returnedNames;
1914     long nextEntryCookie;
1915     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
1916     char *op;                   /* output data ptr */
1917         char *origOp;                   /* original value of op */
1918     cm_space_t *spacep;         /* for pathname buffer */
1919     long maxReturnData;         /* max # of return data */
1920     long maxReturnParms;                /* max # of return parms */
1921     long bytesInBuffer;         /* # data bytes in the output buffer */
1922     int starPattern;
1923     char *maskp;                        /* mask part of path */
1924     int infoLevel;
1925     int searchFlags;
1926     int eos;
1927     smb_tran2Packet_t *outp;    /* response packet */
1928         char *tidPathp;
1929         int align;
1930         char shortName[13];             /* 8.3 name if needed */
1931         int NeedShortName;
1932     int foundInexact;
1933         char *shortNameEnd;
1934     int fileType;
1935     cm_fid_t fid;
1936
1937     cm_req_t req;
1938
1939         cm_InitReq(&req);
1940
1941         eos = 0;
1942         if (p->opcode == 1) {
1943                 /* find first; obtain basic parameters from request */
1944         attribute = p->parmsp[0];
1945         maxCount = p->parmsp[1];
1946         infoLevel = p->parmsp[3];
1947         searchFlags = p->parmsp[2];
1948         dsp = smb_NewDirSearch(1);
1949         dsp->attribute = attribute;
1950         pathp = ((char *) p->parmsp) + 12;      /* points to path */
1951         nextCookie = 0;
1952         maskp = strrchr(pathp, '\\');
1953         if (maskp == NULL) maskp = pathp;
1954                 else maskp++;   /* skip over backslash */
1955         strcpy(dsp->mask, maskp);       /* and save mask */
1956                 /* track if this is likely to match a lot of entries */
1957         starPattern = smb_V3IsStarMask(maskp);
1958         }
1959     else {
1960                 osi_assert(p->opcode == 2);
1961         /* find next; obtain basic parameters from request or open dir file */
1962         dsp = smb_FindDirSearch(p->parmsp[0]);
1963         if (!dsp) return CM_ERROR_BADFD;
1964         attribute = dsp->attribute;
1965         maxCount = p->parmsp[1];
1966         infoLevel = p->parmsp[2];
1967         searchFlags = p->parmsp[5];
1968         pathp = NULL;
1969         nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
1970         maskp = dsp->mask;
1971                 starPattern = 1;        /* assume, since required a Find Next */
1972     }
1973
1974         osi_Log4(smb_logp,
1975               "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
1976               attribute, infoLevel, maxCount, searchFlags);
1977
1978         osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
1979               p->opcode, nextCookie);
1980
1981         if (infoLevel >= 0x101)
1982                 searchFlags &= ~4;      /* no resume keys */
1983
1984     dirListPatchesp = NULL;
1985
1986         maxReturnData = p->maxReturnData;
1987     if (p->opcode == 1) /* find first */
1988         maxReturnParms = 10;    /* bytes */
1989         else    
1990         maxReturnParms = 8;     /* bytes */
1991
1992 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
1993     if (maxReturnData > 6000) 
1994         maxReturnData = 6000;
1995 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
1996
1997         outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
1998                                       maxReturnData);
1999
2000     osi_Log1(smb_logp, "T2 receive search dir %s",
2001              osi_LogSaveString(smb_logp, pathp));
2002         
2003     /* bail out if request looks bad */
2004     if (p->opcode == 1 && !pathp) {
2005         smb_ReleaseDirSearch(dsp);
2006         smb_FreeTran2Packet(outp);
2007         return CM_ERROR_BADSMB;
2008     }
2009         
2010         osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
2011              nextCookie, dsp->cookie);
2012
2013         userp = smb_GetTran2User(vcp, p);
2014     if (!userp) {
2015         osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
2016         smb_ReleaseDirSearch(dsp);
2017         smb_FreeTran2Packet(outp);
2018         return CM_ERROR_BADSMB;
2019     }
2020
2021         /* try to get the vnode for the path name next */
2022         lock_ObtainMutex(&dsp->mx);
2023         if (dsp->scp) {
2024                 scp = dsp->scp;
2025         cm_HoldSCache(scp);
2026         code = 0;
2027     }
2028     else {
2029                 spacep = cm_GetSpace();
2030         smb_StripLastComponent(spacep->data, NULL, pathp);
2031         lock_ReleaseMutex(&dsp->mx);
2032
2033                 tidPathp = smb_GetTIDPath(vcp, p->tid);
2034         code = cm_NameI(cm_rootSCachep, spacep->data,
2035                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2036                         userp, tidPathp, &req, &scp);
2037         cm_FreeSpace(spacep);
2038
2039         lock_ObtainMutex(&dsp->mx);
2040                 if (code == 0) {
2041             if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2042                         dsp->scp = scp;
2043                         /* we need one hold for the entry we just stored into,
2044              * and one for our own processing.  When we're done
2045                          * with this function, we'll drop the one for our own
2046                          * processing.  We held it once from the namei call,
2047                          * and so we do another hold now.
2048              */
2049             cm_HoldSCache(scp);
2050                         lock_ObtainMutex(&scp->mx);
2051                         if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2052                             && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2053                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2054                                 dsp->flags |= SMB_DIRSEARCH_BULKST;
2055                         }
2056                         lock_ReleaseMutex(&scp->mx);
2057         }
2058     }
2059         lock_ReleaseMutex(&dsp->mx);
2060     if (code) {
2061                 cm_ReleaseUser(userp);
2062         smb_FreeTran2Packet(outp);
2063                 smb_DeleteDirSearch(dsp);
2064                 smb_ReleaseDirSearch(dsp);
2065         return code;
2066         }
2067
2068     /* get the directory size */
2069         lock_ObtainMutex(&scp->mx);
2070     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2071                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2072         if (code) {
2073                 lock_ReleaseMutex(&scp->mx);
2074         cm_ReleaseSCache(scp);
2075         cm_ReleaseUser(userp);
2076         smb_FreeTran2Packet(outp);
2077                 smb_DeleteDirSearch(dsp);
2078                 smb_ReleaseDirSearch(dsp);
2079         return code;
2080     }
2081
2082   startsearch:
2083     dirLength = scp->length;
2084     bufferp = NULL;
2085     bufferOffset.LowPart = bufferOffset.HighPart = 0;
2086     curOffset.HighPart = 0;
2087     curOffset.LowPart = nextCookie;
2088         origOp = outp->datap;
2089
2090     foundInexact = 0;
2091     code = 0;
2092     returnedNames = 0;
2093     bytesInBuffer = 0;
2094     while (1) {
2095                 op = origOp;
2096                 if (searchFlags & 4)
2097                         /* skip over resume key */
2098                         op += 4;
2099
2100                 /* make sure that curOffset.LowPart doesn't point to the first
2101          * 32 bytes in the 2nd through last dir page, and that it doesn't
2102          * point at the first 13 32-byte chunks in the first dir page,
2103          * since those are dir and page headers, and don't contain useful
2104          * information.
2105          */
2106                 temp = curOffset.LowPart & (2048-1);
2107         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2108                         /* we're in the first page */
2109             if (temp < 13*32) temp = 13*32;
2110                 }
2111                 else {
2112                         /* we're in a later dir page */
2113             if (temp < 32) temp = 32;
2114         }
2115                 
2116         /* make sure the low order 5 bits are zero */
2117         temp &= ~(32-1);
2118                 
2119         /* now put temp bits back ito curOffset.LowPart */
2120         curOffset.LowPart &= ~(2048-1);
2121         curOffset.LowPart |= temp;
2122
2123         /* check if we've passed the dir's EOF */
2124         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2125             eos = 1;
2126             break;
2127         }
2128
2129         /* check if we've returned all the names that will fit in the
2130          * response packet; we check return count as well as the number
2131          * of bytes requested.  We check the # of bytes after we find
2132          * the dir entry, since we'll need to check its size.
2133          */
2134         if (returnedNames >= maxCount) {
2135             break;
2136         }
2137
2138         /* see if we can use the bufferp we have now; compute in which
2139          * page the current offset would be, and check whether that's
2140          * the offset of the buffer we have.  If not, get the buffer.
2141          */
2142         thyper.HighPart = curOffset.HighPart;
2143         thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2144         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2145                         /* wrong buffer */
2146             if (bufferp) {
2147                 buf_Release(bufferp);
2148                 bufferp = NULL;
2149                         }       
2150                         lock_ReleaseMutex(&scp->mx);
2151                         lock_ObtainRead(&scp->bufCreateLock);
2152             code = buf_Get(scp, &thyper, &bufferp);
2153                         lock_ReleaseRead(&scp->bufCreateLock);
2154
2155                         /* now, if we're doing a star match, do bulk fetching
2156                          * of all of the status info for files in the dir.
2157              */
2158             if (starPattern) {
2159                                 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2160                                           infoLevel, userp,
2161                                           &req);
2162                                 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2163                     && LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
2164                                         /* Don't bulk stat if risking timeout */
2165                                         int now = GetCurrentTime();
2166                                         if (now - req.startTime > 5000) {
2167                                                 scp->bulkStatProgress = thyper;
2168                                                 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2169                                                 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2170                                         } else
2171                         cm_TryBulkStat(scp, &thyper, userp, &req);
2172                                 }
2173                         }
2174
2175             lock_ObtainMutex(&scp->mx);
2176             if (code) break;
2177             bufferOffset = thyper;
2178
2179             /* now get the data in the cache */
2180             while (1) {
2181                                 code = cm_SyncOp(scp, bufferp, userp, &req,
2182                                  PRSFS_LOOKUP,
2183                                  CM_SCACHESYNC_NEEDCALLBACK
2184                                  | CM_SCACHESYNC_READ);
2185                                 if (code) break;
2186                                 
2187                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2188
2189                 /* otherwise, load the buffer and try again */
2190                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2191                                     &req);
2192                 if (code) break;
2193             }
2194             if (code) {
2195                                 buf_Release(bufferp);
2196                 bufferp = NULL;
2197                 break;
2198                         }
2199         }       /* if (wrong buffer) ... */
2200                 
2201         /* now we have the buffer containing the entry we're interested
2202          * in; copy it out if it represents a non-deleted entry.
2203          */
2204                 entryInDir = curOffset.LowPart & (2048-1);
2205         entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2206
2207                 /* page header will help tell us which entries are free.  Page
2208                  * header can change more often than once per buffer, since
2209                  * AFS 3 dir page size may be less than (but not more than)
2210                  * a buffer package buffer.
2211          */
2212                 /* only look intra-buffer */
2213                 temp = curOffset.LowPart & (buf_bufferSize - 1);
2214         temp &= ~(2048 - 1);    /* turn off intra-page bits */
2215                 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2216
2217                 /* now determine which entry we're looking at in the page.
2218                  * If it is free (there's a free bitmap at the start of the
2219                  * dir), we should skip these 32 bytes.
2220          */
2221         slotInPage = (entryInDir & 0x7e0) >> 5;
2222         if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2223                & (1 << (slotInPage & 0x7)))) {
2224                         /* this entry is free */
2225             numDirChunks = 1;   /* only skip this guy */
2226             goto nextEntry;
2227         }
2228
2229                 tp = bufferp->datap + entryInBuffer;
2230         dep = (cm_dirEntry_t *) tp;     /* now points to AFS3 dir entry */
2231
2232         /* while we're here, compute the next entry's location, too,
2233                  * since we'll need it when writing out the cookie into the dir
2234                  * listing stream.
2235          *
2236          * XXXX Probably should do more sanity checking.
2237          */
2238                 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2239                 
2240         /* compute offset of cookie representing next entry */
2241         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
2242
2243                 /* Need 8.3 name? */
2244                 NeedShortName = 0;
2245                 if (infoLevel == 0x104
2246                     && dep->fid.vnode != 0
2247                     && !cm_Is8Dot3(dep->name)) {
2248                         cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2249                         NeedShortName = 1;
2250                 }
2251
2252         /* When matching, we are using doing a case fold if we have a wildcard mask.
2253          * If we get a non-wildcard match, it's a lookup for a specific file. 
2254          */
2255         if (dep->fid.vnode != 0 && 
2256             (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0))
2257               || (NeedShortName
2258                    && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
2259
2260             /* Eliminate entries that don't match requested attributes */
2261             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && 
2262                  smb_IsDotFile(dep->name))
2263                 goto nextEntry; /* no hidden files */
2264                     
2265             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
2266             {
2267                 /* We have already done the cm_TryBulkStat above */
2268                 fid.cell = scp->fid.cell;
2269                 fid.volume = scp->fid.volume;
2270                 fid.vnode = ntohl(dep->fid.vnode);
2271                 fid.unique = ntohl(dep->fid.unique);
2272                 fileType = cm_FindFileType(&fid);
2273                 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
2274                  "has filetype %d", dep->name,
2275                  fileType);*/
2276                 if (fileType == CM_SCACHETYPE_DIRECTORY)
2277                     goto nextEntry;
2278             }
2279
2280                         /* finally check if this name will fit */
2281
2282                         /* standard dir entry stuff */
2283                         if (infoLevel < 0x101)
2284                                 ohbytes = 23;   /* pre-NT */
2285                         else if (infoLevel == 0x103)
2286                                 ohbytes = 12;   /* NT names only */
2287                         else
2288                                 ohbytes = 64;   /* NT */
2289
2290                         if (infoLevel == 0x104)
2291                                 ohbytes += 26;  /* Short name & length */
2292
2293             if (searchFlags & 4) {
2294                 ohbytes += 4;   /* if resume key required */
2295                         }   
2296
2297             if (infoLevel != 1
2298                  && infoLevel != 0x101
2299                  && infoLevel != 0x103)
2300                                 ohbytes += 4;   /* EASIZE */
2301
2302                         /* add header to name & term. null */
2303                         orbytes = onbytes + ohbytes + 1;
2304
2305                         /* now, we round up the record to a 4 byte alignment,
2306                          * and we make sure that we have enough room here for
2307                          * even the aligned version (so we don't have to worry
2308                          * about an * overflow when we pad things out below).
2309                          * That's the reason for the alignment arithmetic below.
2310              */
2311                         if (infoLevel >= 0x101)
2312                                 align = (4 - (orbytes & 3)) & 3;
2313                         else
2314                                 align = 0;
2315                         if (orbytes + bytesInBuffer + align > maxReturnData)
2316                 break;
2317
2318                         /* this is one of the entries to use: it is not deleted
2319                          * and it matches the star pattern we're looking for.
2320                          * Put out the name, preceded by its length.
2321              */
2322                         /* First zero everything else */
2323                         memset(origOp, 0, ohbytes);
2324
2325                         if (infoLevel <= 0x101)
2326                 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2327                         else if (infoLevel == 0x103)
2328                                 *((u_long *)(op + 8)) = onbytes;
2329                         else
2330                                 *((u_long *)(op + 60)) = onbytes;
2331             strcpy(origOp+ohbytes, dep->name);
2332
2333                         /* Short name if requested and needed */
2334             if (infoLevel == 0x104) {
2335                                 if (NeedShortName) {
2336                                         strcpy(op + 70, shortName);
2337                                         *(op + 68) = shortNameEnd - shortName;
2338                                 }
2339                         }
2340
2341             /* now, adjust the # of entries copied */
2342             returnedNames++;
2343
2344                         /* NextEntryOffset and FileIndex */
2345                         if (infoLevel >= 101) {
2346                                 int entryOffset = orbytes + align;
2347                                 *((u_long *)op) = entryOffset;
2348                                 *((u_long *)(op+4)) = nextEntryCookie;
2349                         }
2350
2351             /* now we emit the attribute.  This is tricky, since
2352              * we need to really stat the file to find out what
2353                          * type of entry we've got.  Right now, we're copying
2354                          * out data from * a buffer, while holding the scp
2355                          * locked, so it isn't really convenient to stat
2356                          * something now.  We'll put in a place holder
2357              * now, and make a second pass before returning this
2358                          * to get the real attributes.  So, we just skip the
2359                          * data for now, and adjust it later.  We allocate a
2360                          * patch record to make it easy to find this point
2361                          * later.  The replay will happen at a time when it is
2362                          * safe to unlock the directory.
2363              */
2364                         if (infoLevel != 0x103) {
2365                                 curPatchp = malloc(sizeof(*curPatchp));
2366                 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2367                           &curPatchp->q);
2368                                 curPatchp->dptr = op;
2369                                 if (infoLevel >= 0x101)
2370                                         curPatchp->dptr += 8;
2371
2372                 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
2373                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
2374                 }
2375                 else
2376                     curPatchp->flags = 0;
2377
2378                                 curPatchp->fid.cell = scp->fid.cell;
2379                                 curPatchp->fid.volume = scp->fid.volume;
2380                                 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2381                                 curPatchp->fid.unique = ntohl(dep->fid.unique);
2382
2383                 /* temp */
2384                 curPatchp->dep = dep;
2385                         }   
2386
2387                         if (searchFlags & 4)
2388                                 /* put out resume key */
2389                                 *((u_long *)origOp) = nextEntryCookie;
2390
2391                         /* Adjust byte ptr and count */
2392                         origOp += orbytes;      /* skip entire record */
2393             bytesInBuffer += orbytes;
2394
2395                         /* and pad the record out */
2396             while (--align >= 0) {
2397                                 *origOp++ = 0;
2398                 bytesInBuffer++;
2399             }
2400
2401                 }       /* if we're including this name */
2402         else if(!NeedShortName &&
2403                  !starPattern &&
2404                  !foundInexact &&
2405                                                         dep->fid.vnode != 0 &&
2406                  smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
2407             /* We were looking for exact matches, but here's an inexact one*/
2408             foundInexact = 1;
2409         }
2410                 
2411       nextEntry:
2412         /* and adjust curOffset to be where the new cookie is */
2413                 thyper.HighPart = 0;
2414         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2415         curOffset = LargeIntegerAdd(thyper, curOffset);
2416     }           /* while copying data for dir listing */
2417
2418     /* If we didn't get a star pattern, we did an exact match during the first pass. 
2419      * If there were no exact matches found, we fail over to inexact matches by
2420      * marking the query as a star pattern (matches all case permutations), and
2421      * re-running the query. 
2422      */
2423     if (returnedNames == 0 && !starPattern && foundInexact) {
2424         osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
2425         starPattern = 1;
2426         goto startsearch;
2427     }
2428
2429         /* release the mutex */
2430         lock_ReleaseMutex(&scp->mx);
2431     if (bufferp) buf_Release(bufferp);
2432
2433         /* apply and free last set of patches; if not doing a star match, this
2434          * will be empty, but better safe (and freeing everything) than sorry.
2435      */
2436     smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2437                               &req);
2438         
2439     /* now put out the final parameters */
2440         if (returnedNames == 0) eos = 1;
2441     if (p->opcode == 1) {
2442                 /* find first */
2443         outp->parmsp[0] = (unsigned short) dsp->cookie;
2444         outp->parmsp[1] = returnedNames;
2445         outp->parmsp[2] = eos;
2446         outp->parmsp[3] = 0;            /* nothing wrong with EAS */
2447         outp->parmsp[4] = 0;    
2448         /* don't need last name to continue
2449          * search, cookie is enough.  Normally,
2450          * this is the offset of the file name
2451          * of the last entry returned.
2452          */
2453         outp->totalParms = 10;  /* in bytes */
2454     }
2455     else {
2456         /* find next */
2457         outp->parmsp[0] = returnedNames;
2458         outp->parmsp[1] = eos;
2459         outp->parmsp[2] = 0;    /* EAS error */
2460         outp->parmsp[3] = 0;    /* last name, as above */
2461         outp->totalParms = 8;   /* in bytes */
2462     }   
2463
2464         /* return # of bytes in the buffer */
2465     outp->totalData = bytesInBuffer;
2466
2467         osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
2468               returnedNames, code);
2469
2470         /* Return error code if unsuccessful on first request */
2471         if (code == 0 && p->opcode == 1 && returnedNames == 0)
2472                 code = CM_ERROR_NOSUCHFILE;
2473
2474         /* if we're supposed to close the search after this request, or if
2475      * we're supposed to close the search if we're done, and we're done,
2476      * or if something went wrong, close the search.
2477      */
2478     /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2479         if ((searchFlags & 1) || (returnedNames == 0) || 
2480          ((searchFlags & 2) && eos) || code != 0)
2481             smb_DeleteDirSearch(dsp);
2482         if (code)
2483         smb_SendTran2Error(vcp, p, opx, code);
2484         else {
2485         smb_SendTran2Packet(vcp, outp, opx);
2486         }
2487         smb_FreeTran2Packet(outp);
2488     smb_ReleaseDirSearch(dsp);
2489     cm_ReleaseSCache(scp);
2490     cm_ReleaseUser(userp);
2491     return 0;
2492 }
2493
2494 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2495 {
2496     int dirHandle;
2497     smb_dirSearch_t *dsp;
2498
2499     dirHandle = smb_GetSMBParm(inp, 0);
2500         
2501     osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
2502
2503     dsp = smb_FindDirSearch(dirHandle);
2504         
2505     if (!dsp)
2506                 return CM_ERROR_BADFD;
2507         
2508     /* otherwise, we have an FD to destroy */
2509     smb_DeleteDirSearch(dsp);
2510     smb_ReleaseDirSearch(dsp);
2511         
2512         /* and return results */
2513         smb_SetSMBDataLength(outp, 0);
2514
2515     return 0;
2516 }
2517
2518 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2519 {
2520         smb_SetSMBDataLength(outp, 0);
2521     return 0;
2522 }
2523
2524 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2525 {
2526         char *pathp;
2527     long code = 0;
2528         cm_space_t *spacep;
2529     int excl;
2530     cm_user_t *userp;
2531     cm_scache_t *dscp;          /* dir we're dealing with */
2532     cm_scache_t *scp;           /* file we're creating */
2533     cm_attr_t setAttr;
2534     int initialModeBits;
2535     smb_fid_t *fidp;
2536     int attributes;
2537     char *lastNamep;
2538     long dosTime;
2539     int openFun;
2540     int trunc;
2541     int openMode;
2542     int extraInfo;
2543     int openAction;
2544     int parmSlot;                       /* which parm we're dealing with */
2545         char *tidPathp;
2546         cm_req_t req;
2547
2548         cm_InitReq(&req);
2549
2550     scp = NULL;
2551         
2552         extraInfo = (smb_GetSMBParm(inp, 2) & 1);       /* return extra info */
2553         openFun = smb_GetSMBParm(inp, 8);       /* open function */
2554     excl = ((openFun & 3) == 0);
2555     trunc = ((openFun & 3) == 2);               /* truncate it */
2556         openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2557     openAction = 0;                     /* tracks what we did */
2558
2559     attributes = smb_GetSMBParm(inp, 5);
2560     dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2561
2562         /* compute initial mode bits based on read-only flag in attributes */
2563     initialModeBits = 0666;
2564     if (attributes & 1) initialModeBits &= ~0222;
2565         
2566     pathp = smb_GetSMBData(inp, NULL);
2567
2568         spacep = inp->spacep;
2569     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2570
2571         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2572                 /* special case magic file name for receiving IOCTL requests
2573          * (since IOCTL calls themselves aren't getting through).
2574          */
2575 #ifdef NOTSERVICE
2576         osi_Log0(smb_logp, "IOCTL Open");
2577 #endif
2578
2579         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2580         smb_SetupIoctlFid(fidp, spacep);
2581
2582                 /* set inp->fid so that later read calls in same msg can find fid */
2583         inp->fid = fidp->fid;
2584         
2585         /* copy out remainder of the parms */
2586                 parmSlot = 2;
2587                 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2588                 if (extraInfo) {
2589             smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2590             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* mod time */
2591             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2592             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* len */
2593             smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2594             smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2595             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2596             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2597                 }   
2598                 /* and the final "always present" stuff */
2599         smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2600                 /* next write out the "unique" ID */
2601                 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2602                 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2603         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2604         smb_SetSMBDataLength(outp, 0);
2605
2606                 /* and clean up fid reference */
2607         smb_ReleaseFID(fidp);
2608         return 0;
2609     }
2610
2611 #ifdef DEBUG_VERBOSE
2612     {
2613         char *hexp, *asciip;
2614         asciip = (lastNamep ? lastNamep : pathp );
2615         hexp = osi_HexifyString(asciip);
2616         DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
2617         free(hexp);
2618     }
2619 #endif
2620     userp = smb_GetUser(vcp, inp);
2621
2622         dscp = NULL;
2623         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2624         code = cm_NameI(cm_rootSCachep, pathp,
2625                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2626                     userp, tidPathp, &req, &scp);
2627         if (code != 0) {
2628                 code = cm_NameI(cm_rootSCachep, spacep->data,
2629                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2630                         userp, tidPathp, &req, &dscp);
2631
2632         if (code) {
2633             cm_ReleaseUser(userp);
2634             return code;
2635         }
2636         
2637         /* otherwise, scp points to the parent directory.  Do a lookup,
2638          * and truncate the file if we find it, otherwise we create the
2639          * file.
2640          */
2641         if (!lastNamep) lastNamep = pathp;
2642         else lastNamep++;
2643         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2644                           &req, &scp);
2645         if (code && code != CM_ERROR_NOSUCHFILE) {
2646                         cm_ReleaseSCache(dscp);
2647             cm_ReleaseUser(userp);
2648             return code;
2649         }
2650         }
2651         
2652     /* if we get here, if code is 0, the file exists and is represented by
2653      * scp.  Otherwise, we have to create it.  The dir may be represented
2654      * by dscp, or we may have found the file directly.  If code is non-zero,
2655      * scp is NULL.
2656      */
2657         if (code == 0) {
2658         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2659         if (code) {
2660             if (dscp) cm_ReleaseSCache(dscp);
2661             cm_ReleaseSCache(scp);
2662             cm_ReleaseUser(userp);
2663             return code;
2664         }
2665
2666                 if (excl) {
2667                         /* oops, file shouldn't be there */
2668             if (dscp) cm_ReleaseSCache(dscp);
2669             cm_ReleaseSCache(scp);
2670             cm_ReleaseUser(userp);
2671             return CM_ERROR_EXISTS;
2672         }
2673
2674                 if (trunc) {
2675                         setAttr.mask = CM_ATTRMASK_LENGTH;
2676             setAttr.length.LowPart = 0;
2677             setAttr.length.HighPart = 0;
2678                         code = cm_SetAttr(scp, &setAttr, userp, &req);
2679             openAction = 3;     /* truncated existing file */
2680                 }
2681         else openAction = 1;    /* found existing file */
2682     }
2683         else if (!(openFun & 0x10)) {
2684                 /* don't create if not found */
2685         if (dscp) cm_ReleaseSCache(dscp);
2686         cm_ReleaseUser(userp);
2687         return CM_ERROR_NOSUCHFILE;
2688     }
2689     else {
2690                 osi_assert(dscp != NULL);
2691                 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
2692                  osi_LogSaveString(smb_logp, lastNamep));
2693                 openAction = 2; /* created file */
2694                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2695                 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2696         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2697                          &req);
2698                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2699                         smb_NotifyChange(FILE_ACTION_ADDED,
2700                              FILE_NOTIFY_CHANGE_FILE_NAME,
2701                              dscp, lastNamep, NULL, TRUE);
2702         if (!excl && code == CM_ERROR_EXISTS) {
2703                         /* not an exclusive create, and someone else tried
2704                          * creating it already, then we open it anyway.  We
2705                          * don't bother retrying after this, since if this next
2706                          * fails, that means that the file was deleted after we
2707                          * started this call.
2708              */
2709             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2710                              userp, &req, &scp);
2711             if (code == 0) {
2712                 if (trunc) {
2713                                         setAttr.mask = CM_ATTRMASK_LENGTH;
2714                     setAttr.length.LowPart = 0;
2715                     setAttr.length.HighPart = 0;
2716                     code = cm_SetAttr(scp, &setAttr, userp, &req);
2717                 }   
2718                         }       /* lookup succeeded */
2719         }
2720     }
2721         
2722         /* we don't need this any longer */
2723         if (dscp) cm_ReleaseSCache(dscp);
2724
2725     if (code) {
2726                 /* something went wrong creating or truncating the file */
2727         if (scp) cm_ReleaseSCache(scp);
2728         cm_ReleaseUser(userp);
2729         return code;
2730     }
2731         
2732         /* make sure we're about to open a file */
2733         if (scp->fileType != CM_SCACHETYPE_FILE) {
2734                 cm_ReleaseSCache(scp);
2735                 cm_ReleaseUser(userp);
2736                 return CM_ERROR_ISDIR;
2737         }
2738
2739     /* now all we have to do is open the file itself */
2740     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2741     osi_assert(fidp);
2742         
2743         /* save a pointer to the vnode */
2744     fidp->scp = scp;
2745         
2746         /* compute open mode */
2747     if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2748     if (openMode == 1 || openMode == 2)
2749         fidp->flags |= SMB_FID_OPENWRITE;
2750
2751         smb_ReleaseFID(fidp);
2752         
2753         cm_Open(scp, 0, userp);
2754
2755         /* set inp->fid so that later read calls in same msg can find fid */
2756     inp->fid = fidp->fid;
2757         
2758     /* copy out remainder of the parms */
2759         parmSlot = 2;
2760         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2761         lock_ObtainMutex(&scp->mx);
2762         if (extraInfo) {
2763         smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2764                 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2765         smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2766         smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2767         smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2768         smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2769         smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2770         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2771         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2772         }
2773         /* and the final "always present" stuff */
2774     smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2775         /* next write out the "unique" ID */
2776         smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2777         smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2778     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2779         lock_ReleaseMutex(&scp->mx);
2780     smb_SetSMBDataLength(outp, 0);
2781
2782         osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
2783
2784     cm_ReleaseUser(userp);
2785     /* leave scp held since we put it in fidp->scp */
2786     return 0;
2787 }   
2788
2789 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2790 {
2791         cm_req_t req;
2792         cm_user_t *userp;
2793         unsigned short fid;
2794         smb_fid_t *fidp;
2795         cm_scache_t *scp;
2796         unsigned char LockType;
2797         unsigned short NumberOfUnlocks, NumberOfLocks;
2798         unsigned long Timeout;
2799         char *op;
2800         LARGE_INTEGER LOffset, LLength;
2801         smb_waitingLock_t *waitingLock;
2802         void *lockp;
2803         long code = 0;
2804         int i;
2805
2806         cm_InitReq(&req);
2807
2808         fid = smb_GetSMBParm(inp, 2);
2809         fid = smb_ChainFID(fid, inp);
2810
2811         fidp = smb_FindFID(vcp, fid, 0);
2812         if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2813                 return CM_ERROR_BADFD;
2814         }
2815         /* set inp->fid so that later read calls in same msg can find fid */
2816     inp->fid = fid;
2817
2818         userp = smb_GetUser(vcp, inp);
2819
2820         scp = fidp->scp;
2821
2822         lock_ObtainMutex(&scp->mx);
2823         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2824                          CM_SCACHESYNC_NEEDCALLBACK
2825                          | CM_SCACHESYNC_GETSTATUS
2826                          | CM_SCACHESYNC_LOCK);
2827         if (code) goto doneSync;
2828
2829         LockType = smb_GetSMBParm(inp, 3) & 0xff;
2830         Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2831         NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2832         NumberOfLocks = smb_GetSMBParm(inp, 7);
2833
2834         op = smb_GetSMBData(inp, NULL);
2835
2836         for (i=0; i<NumberOfUnlocks; i++) {
2837                 if (LockType & 0x10) {
2838                         /* Large Files */
2839                         LOffset.HighPart = *((LONG *)(op + 4));
2840                         LOffset.LowPart = *((DWORD *)(op + 8));
2841                         LLength.HighPart = *((LONG *)(op + 12));
2842                         LLength.LowPart = *((DWORD *)(op + 16));
2843                         op += 20;
2844                 }
2845                 else {
2846                         /* Not Large Files */
2847                         LOffset.HighPart = 0;
2848                         LOffset.LowPart = *((DWORD *)(op + 2));
2849                         LLength.HighPart = 0;
2850                         LLength.LowPart = *((DWORD *)(op + 6));
2851                         op += 10;
2852                 }
2853                 if (LargeIntegerNotEqualToZero(LOffset))
2854                         continue;
2855                 /* Do not check length -- length check done in cm_Unlock */
2856
2857                 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2858                 if (code) goto done;
2859         }
2860
2861         for (i=0; i<NumberOfLocks; i++) {
2862                 if (LockType & 0x10) {
2863                         /* Large Files */
2864                         LOffset.HighPart = *((LONG *)(op + 4));
2865                         LOffset.LowPart = *((DWORD *)(op + 8));
2866                         LLength.HighPart = *((LONG *)(op + 12));
2867                         LLength.LowPart = *((DWORD *)(op + 16));
2868                         op += 20;
2869                 }
2870                 else {
2871                         /* Not Large Files */
2872                         LOffset.HighPart = 0;
2873                         LOffset.LowPart = *((DWORD *)(op + 2));
2874                         LLength.HighPart = 0;
2875                         LLength.LowPart = *((DWORD *)(op + 6));
2876                         op += 10;
2877                 }
2878                 if (LargeIntegerNotEqualToZero(LOffset))
2879                         continue;
2880                 if (LargeIntegerLessThan(LOffset, scp->length))
2881                         continue;
2882
2883                 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2884                                 userp, &req, &lockp);
2885                 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2886                         /* Put on waiting list */
2887                         waitingLock = malloc(sizeof(smb_waitingLock_t));
2888                         waitingLock->vcp = vcp;
2889                         waitingLock->inp = smb_CopyPacket(inp);
2890                         waitingLock->outp = smb_CopyPacket(outp);
2891                         waitingLock->timeRemaining = Timeout;
2892                         waitingLock->lockp = lockp;
2893                         lock_ObtainWrite(&smb_globalLock);
2894                         osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2895                                  &waitingLock->q);
2896                         osi_Wakeup((long) &smb_allWaitingLocks);
2897                         lock_ReleaseWrite(&smb_globalLock);
2898                         /* don't send reply immediately */
2899                         outp->flags |= SMB_PACKETFLAG_NOSEND;
2900                 }
2901                 if (code) break;
2902         }
2903
2904         if (code) {
2905                 /* release any locks acquired before the failure */
2906         }
2907         else
2908                 smb_SetSMBDataLength(outp, 0);
2909 done:
2910         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2911 doneSync:
2912         lock_ReleaseMutex(&scp->mx);
2913         cm_ReleaseUser(userp);
2914         smb_ReleaseFID(fidp);
2915
2916         return code;
2917 }
2918
2919 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2920 {
2921         unsigned short fid;
2922     smb_fid_t *fidp;
2923     cm_scache_t *scp;
2924     long code = 0;
2925     long searchTime;
2926     cm_user_t *userp;
2927         cm_req_t req;
2928
2929         cm_InitReq(&req);
2930
2931     fid = smb_GetSMBParm(inp, 0);
2932     fid = smb_ChainFID(fid, inp);
2933         
2934     fidp = smb_FindFID(vcp, fid, 0);
2935     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2936                 return CM_ERROR_BADFD;
2937     }
2938         
2939     userp = smb_GetUser(vcp, inp);
2940         
2941     scp = fidp->scp;
2942         
2943     /* otherwise, stat the file */
2944         lock_ObtainMutex(&scp->mx);
2945     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2946                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2947         if (code) goto done;
2948
2949         /* decode times.  We need a search time, but the response to this
2950      * call provides the date first, not the time, as returned in the
2951      * searchTime variable.  So we take the high-order bits first.
2952      */
2953         smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2954     smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff);       /* ctime */
2955     smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2956     smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff);       /* atime */
2957     smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2958     smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff);       /* mtime */
2959     smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2960
2961     /* now handle file size and allocation size */
2962     smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff);              /* file size */
2963     smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2964     smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff);              /* alloc size */
2965     smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2966
2967         /* file attribute */
2968     smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2969         
2970     /* and finalize stuff */
2971     smb_SetSMBDataLength(outp, 0);
2972     code = 0;
2973
2974   done:
2975         lock_ReleaseMutex(&scp->mx);
2976         cm_ReleaseUser(userp);
2977         smb_ReleaseFID(fidp);
2978         return code;
2979 }
2980
2981 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2982 {
2983         unsigned short fid;
2984     smb_fid_t *fidp;
2985     cm_scache_t *scp;
2986     long code = 0;
2987         long searchTime;
2988     long unixTime;
2989     cm_user_t *userp;
2990     cm_attr_t attrs;
2991         cm_req_t req;
2992
2993         cm_InitReq(&req);
2994
2995     fid = smb_GetSMBParm(inp, 0);
2996     fid = smb_ChainFID(fid, inp);
2997         
2998     fidp = smb_FindFID(vcp, fid, 0);
2999     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
3000                 return CM_ERROR_BADFD;
3001     }
3002         
3003     userp = smb_GetUser(vcp, inp);
3004         
3005     scp = fidp->scp;
3006         
3007         /* now prepare to call cm_setattr.  This message only sets various times,
3008      * and AFS only implements mtime, and we'll set the mtime if that's
3009      * requested.  The others we'll ignore.
3010      */
3011         searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
3012         
3013     if (searchTime != 0) {
3014                 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
3015
3016         if ( unixTime != -1 ) {
3017             attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
3018             attrs.clientModTime = unixTime;
3019             code = cm_SetAttr(scp, &attrs, userp, &req);
3020
3021             osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
3022         } else {
3023             osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
3024         }
3025     }
3026     else code = 0;
3027
3028         cm_ReleaseUser(userp);
3029         smb_ReleaseFID(fidp);
3030         return code;
3031 }
3032
3033
3034 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3035 {
3036         osi_hyper_t offset;
3037     long count, finalCount;
3038     unsigned short fd;
3039     smb_fid_t *fidp;
3040     long code = 0;
3041     cm_user_t *userp;
3042     char *op;
3043         
3044     fd = smb_GetSMBParm(inp, 2);
3045     count = smb_GetSMBParm(inp, 5);
3046     offset.HighPart = 0;        /* too bad */
3047     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
3048
3049     osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
3050              fd, offset.LowPart, count);
3051         
3052         fd = smb_ChainFID(fd, inp);
3053     fidp = smb_FindFID(vcp, fd, 0);
3054     if (!fidp) {
3055                 return CM_ERROR_BADFD;
3056     }
3057         /* set inp->fid so that later read calls in same msg can find fid */
3058     inp->fid = fd;
3059
3060     if (fidp->flags & SMB_FID_IOCTL) {
3061                 return smb_IoctlV3Read(fidp, vcp, inp, outp);
3062     }
3063         
3064         userp = smb_GetUser(vcp, inp);
3065
3066         /* 0 and 1 are reserved for request chaining, were setup by our caller,
3067      * and will be further filled in after we return.
3068      */
3069     smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
3070     smb_SetSMBParm(outp, 3, 0); /* resvd */
3071     smb_SetSMBParm(outp, 4, 0); /* resvd */
3072         smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
3073     /* fill in #6 when we have all the parameters' space reserved */
3074     smb_SetSMBParm(outp, 7, 0); /* resv'd */
3075     smb_SetSMBParm(outp, 8, 0); /* resv'd */
3076     smb_SetSMBParm(outp, 9, 0); /* resv'd */
3077     smb_SetSMBParm(outp, 10, 0);        /* resv'd */
3078         smb_SetSMBParm(outp, 11, 0);    /* reserved */
3079
3080         /* get op ptr after putting in the parms, since otherwise we don't
3081      * know where the data really is.
3082      */
3083     op = smb_GetSMBData(outp, NULL);
3084         
3085     /* now fill in offset from start of SMB header to first data byte (to op) */
3086     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
3087
3088         /* set the packet data length the count of the # of bytes */
3089     smb_SetSMBDataLength(outp, count);
3090
3091 #ifndef DJGPP
3092         code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
3093 #else /* DJGPP */
3094         code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
3095 #endif /* !DJGPP */
3096
3097         /* fix some things up */
3098         smb_SetSMBParm(outp, 5, finalCount);
3099         smb_SetSMBDataLength(outp, finalCount);
3100
3101     smb_ReleaseFID(fidp);
3102
3103     cm_ReleaseUser(userp);
3104     return code;
3105 }   
3106         
3107 /*
3108  * Values for createDisp, copied from NTDDK.H
3109  *
3110  *  FILE_SUPERSEDE      0       (???)
3111  *  FILE_OPEN           1       (open)
3112  *  FILE_CREATE         2       (exclusive)
3113  *  FILE_OPEN_IF        3       (non-exclusive)
3114  *  FILE_OVERWRITE      4       (open & truncate, but do not create)
3115  *  FILE_OVERWRITE_IF   5       (open & truncate, or create)
3116  */
3117
3118 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3119 {
3120         char *pathp, *realPathp;
3121         long code = 0;
3122         cm_space_t *spacep;
3123         cm_user_t *userp;
3124         cm_scache_t *dscp;              /* parent dir */
3125         cm_scache_t *scp;               /* file to create or open */
3126         cm_attr_t setAttr;
3127         char *lastNamep;
3128     char *treeStartp;
3129         unsigned short nameLength;
3130         unsigned int flags;
3131         unsigned int requestOpLock;
3132         unsigned int requestBatchOpLock;
3133         unsigned int mustBeDir;
3134     unsigned int treeCreate;
3135         int realDirFlag;
3136         unsigned int desiredAccess;
3137         unsigned int extAttributes;
3138         unsigned int createDisp;
3139         unsigned int createOptions;
3140         int initialModeBits;
3141         unsigned short baseFid;
3142         smb_fid_t *baseFidp;
3143         smb_fid_t *fidp;
3144         cm_scache_t *baseDirp;
3145         unsigned short openAction;
3146         int parmSlot;
3147         long fidflags;
3148         FILETIME ft;
3149         LARGE_INTEGER sz;
3150         char *tidPathp;
3151         BOOL foundscp;
3152         cm_req_t req;
3153
3154         cm_InitReq(&req);
3155
3156     treeCreate = FALSE;
3157         foundscp = FALSE;
3158         scp = NULL;
3159
3160         nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3161         flags = smb_GetSMBOffsetParm(inp, 3, 1)
3162                   | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3163         requestOpLock = flags & 0x02;
3164         requestBatchOpLock = flags & 0x04;
3165         mustBeDir = flags & 0x08;
3166
3167         /*
3168          * Why all of a sudden 32-bit FID?
3169          * We will reject all bits higher than 16.
3170          */
3171         if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3172                 return CM_ERROR_INVAL;
3173         baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3174         desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3175                           | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3176         extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3177                           | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3178         createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3179                         | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3180         createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3181                           | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3182
3183         /* mustBeDir is never set; createOptions directory bit seems to be
3184          * more important
3185          */
3186         if (createOptions & 1)
3187                 realDirFlag = 1;
3188         else if (createOptions & 0x40)
3189                 realDirFlag = 0;
3190         else
3191                 realDirFlag = -1;
3192
3193         /*
3194          * compute initial mode bits based on read-only flag in
3195          * extended attributes
3196          */
3197         initialModeBits = 0666;
3198         if (extAttributes & 1) initialModeBits &= ~0222;
3199
3200         pathp = smb_GetSMBData(inp, NULL);
3201         /* Sometimes path is not null-terminated, so we make a copy. */
3202         realPathp = malloc(nameLength+1);
3203         memcpy(realPathp, pathp, nameLength);
3204         realPathp[nameLength] = 0;
3205
3206         spacep = inp->spacep;
3207         smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3208
3209     osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
3210     osi_Log4(smb_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
3211
3212         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3213                 /* special case magic file name for receiving IOCTL requests
3214                  * (since IOCTL calls themselves aren't getting through).
3215                  */
3216                 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3217                 smb_SetupIoctlFid(fidp, spacep);
3218
3219                 /* set inp->fid so that later read calls in same msg can find fid */
3220                 inp->fid = fidp->fid;
3221
3222                 /* out parms */
3223                 parmSlot = 2;
3224                 smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
3225                 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3226                 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3227                 /* times */
3228                 memset(&ft, 0, sizeof(ft));
3229                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3230                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3231                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3232                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3233                 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3234                 sz.HighPart = 0x7fff; sz.LowPart = 0;
3235                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3236                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3237                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
3238                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
3239                 smb_SetSMBParmByte(outp, parmSlot, 0);  /* is a dir? */
3240                 smb_SetSMBDataLength(outp, 0);
3241
3242                 /* clean up fid reference */
3243                 smb_ReleaseFID(fidp);
3244                 free(realPathp);
3245                 return 0;
3246         }
3247
3248 #ifdef DEBUG_VERBOSE
3249     {
3250         char *hexp, *asciip;
3251         asciip = (lastNamep? lastNamep : realPathp);
3252         hexp = osi_HexifyString( asciip );
3253         DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
3254         free(hexp);
3255     }
3256 #endif
3257     userp = smb_GetUser(vcp, inp);
3258     if (!userp) {
3259         osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
3260         free(realPathp);
3261         return CM_ERROR_INVAL;
3262     }
3263
3264         if (baseFid == 0) {
3265                 baseDirp = cm_rootSCachep;
3266                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3267         }
3268         else {
3269         baseFidp = smb_FindFID(vcp, baseFid, 0);
3270         if (!baseFidp) {
3271                 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
3272                 free(realPathp);
3273                 cm_ReleaseUser(userp);
3274                 return CM_ERROR_INVAL;
3275         }
3276                 baseDirp = baseFidp->scp;
3277                 tidPathp = NULL;
3278         }
3279
3280     osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
3281         
3282     /* compute open mode */
3283         fidflags = 0;
3284         if (desiredAccess & DELETE)
3285                 fidflags |= SMB_FID_OPENDELETE;
3286         if (desiredAccess & AFS_ACCESS_READ)
3287                 fidflags |= SMB_FID_OPENREAD;
3288         if (desiredAccess & AFS_ACCESS_WRITE)
3289                 fidflags |= SMB_FID_OPENWRITE;
3290
3291         dscp = NULL;
3292         code = 0;
3293     /* For an exclusive create, we want to do a case sensitive match for the last component. */
3294     if (createDisp == 2 || createDisp == 4) {
3295         code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3296                         userp, tidPathp, &req, &dscp);
3297         if(code == 0) {
3298             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
3299                              userp, tidPathp, &req, &scp);
3300         } else
3301             dscp = NULL;
3302     } else {
3303         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3304                         userp, tidPathp, &req, &scp);
3305     }
3306         
3307     if (code == 0) foundscp = TRUE;
3308         if (code != 0
3309             || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3310                 /* look up parent directory */
3311         /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
3312          * the immediate parent.  We have to work our way up realPathp until we hit something that we
3313          * recognize.
3314          */
3315
3316         if ( !dscp ) {
3317         while(1) {
3318             char *tp;
3319
3320             code = cm_NameI(baseDirp, spacep->data,
3321                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3322                              userp, tidPathp, &req, &dscp);
3323
3324             if (code && 
3325                 (tp = strrchr(spacep->data,'\\')) &&
3326                 (createDisp == 2) &&
3327                 (realDirFlag == 1)) {
3328                 *tp++ = 0;
3329                 treeCreate = TRUE;
3330                 treeStartp = realPathp + (tp - spacep->data);
3331
3332                 if (*tp && !smb_IsLegalFilename(tp)) {
3333                     if(baseFid != 0) smb_ReleaseFID(baseFidp);
3334                     cm_ReleaseUser(userp);
3335                     free(realPathp);
3336                     return CM_ERROR_BADNTFILENAME;
3337                 }
3338             }
3339             else
3340                 break;
3341         }
3342         } else
3343             code = 0;
3344
3345         if (baseFid != 0) smb_ReleaseFID(baseFidp);
3346
3347         if (code) {
3348             osi_Log0(smb_logp,"NTCreateX parent not found");
3349             cm_ReleaseUser(userp);
3350             free(realPathp);
3351             return code;
3352         }
3353
3354         if(treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
3355             /* A file exists where we want a directory. */
3356             cm_ReleaseSCache(dscp);
3357             cm_ReleaseUser(userp);
3358             free(realPathp);
3359             return CM_ERROR_EXISTS;
3360         }
3361
3362         if (!lastNamep) lastNamep = realPathp;
3363         else lastNamep++;
3364
3365         if (!smb_IsLegalFilename(lastNamep)) {
3366             cm_ReleaseSCache(dscp);
3367             cm_ReleaseUser(userp);
3368             free(realPathp);
3369             return CM_ERROR_BADNTFILENAME;
3370         }
3371
3372         if (!foundscp && !treeCreate) {
3373             if(createDisp == 2 || createDisp == 4)
3374                 code = cm_Lookup(dscp, lastNamep,
3375                                   CM_FLAG_FOLLOW, userp, &req, &scp);
3376             else
3377                 code = cm_Lookup(dscp, lastNamep,
3378                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3379                                  userp, &req, &scp);
3380                         if (code && code != CM_ERROR_NOSUCHFILE) {
3381                                 cm_ReleaseSCache(dscp);
3382                                 cm_ReleaseUser(userp);
3383                                 free(realPathp);
3384                                 return code;
3385                         }
3386                 }
3387         }
3388         else {
3389                 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3390         }
3391
3392         /* if we get here, if code is 0, the file exists and is represented by
3393          * scp.  Otherwise, we have to create it.  The dir may be represented
3394          * by dscp, or we may have found the file directly.  If code is non-zero,
3395          * scp is NULL.
3396          */
3397         if (code == 0 && !treeCreate) {
3398                 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3399                                       &req);
3400                 if (code) {
3401                         if (dscp) cm_ReleaseSCache(dscp);
3402                         cm_ReleaseSCache(scp);
3403                         cm_ReleaseUser(userp);
3404                         free(realPathp);
3405                         return code;
3406                 }
3407
3408                 if (createDisp == 2) {
3409                         /* oops, file shouldn't be there */
3410                         if (dscp) cm_ReleaseSCache(dscp);
3411                         cm_ReleaseSCache(scp);
3412                         cm_ReleaseUser(userp);
3413                         free(realPathp);
3414                         return CM_ERROR_EXISTS;
3415                 }
3416
3417                 if (createDisp == 4
3418                     || createDisp == 5) {
3419                         setAttr.mask = CM_ATTRMASK_LENGTH;
3420                         setAttr.length.LowPart = 0;
3421                         setAttr.length.HighPart = 0;
3422                         code = cm_SetAttr(scp, &setAttr, userp, &req);
3423                         openAction = 3; /* truncated existing file */
3424                 }
3425                 else openAction = 1;    /* found existing file */
3426         }
3427         else if (createDisp == 1 || createDisp == 4) {
3428                 /* don't create if not found */
3429                 if (dscp) cm_ReleaseSCache(dscp);
3430                 cm_ReleaseUser(userp);
3431                 free(realPathp);
3432                 return CM_ERROR_NOSUCHFILE;
3433         }
3434         else if (realDirFlag == 0 || realDirFlag == -1) {
3435                 osi_assert(dscp != NULL);
3436                 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
3437                                 osi_LogSaveString(smb_logp, lastNamep));
3438                 openAction = 2;         /* created file */
3439                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3440                 setAttr.clientModTime = time(NULL);
3441                 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3442                                  &req);
3443                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3444                         smb_NotifyChange(FILE_ACTION_ADDED,
3445                                          FILE_NOTIFY_CHANGE_FILE_NAME,
3446                                          dscp, lastNamep, NULL, TRUE);
3447                 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3448                         /* Not an exclusive create, and someone else tried
3449                          * creating it already, then we open it anyway.  We
3450                          * don't bother retrying after this, since if this next
3451                          * fails, that means that the file was deleted after we
3452                          * started this call.
3453                          */
3454                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3455                                          userp, &req, &scp);
3456                         if (code == 0) {
3457                                 if (createDisp == 5) {
3458                                         setAttr.mask = CM_ATTRMASK_LENGTH;
3459                                         setAttr.length.LowPart = 0;
3460                                         setAttr.length.HighPart = 0;
3461                                         code = cm_SetAttr(scp, &setAttr, userp,
3462                                                           &req);
3463                                 }
3464                         }       /* lookup succeeded */
3465                 }
3466         }
3467         else {
3468         char *tp, *pp;
3469         char *cp; /* This component */
3470         int clen = 0; /* length of component */
3471         cm_scache_t *tscp;
3472         int isLast = 0;
3473                 
3474         /* create directory */
3475                 if ( !treeCreate ) treeStartp = lastNamep;
3476         osi_assert(dscp != NULL);
3477         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
3478                                 osi_LogSaveString(smb_logp, treeStartp));
3479                 openAction = 2;         /* created directory */
3480
3481                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3482                 setAttr.clientModTime = time(NULL);
3483                 
3484                 pp = treeStartp;
3485                 cp = spacep->data;
3486                 tscp = dscp;
3487
3488                 while(pp && *pp) {
3489                         tp = strchr(pp, '\\');
3490                         if(!tp) {
3491                                 strcpy(cp,pp);
3492                 clen = strlen(cp);
3493                                 isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
3494                         }
3495                         else {
3496                                 clen = tp - pp;
3497                                 strncpy(cp,pp,clen);
3498                                 *(cp + clen) = 0;
3499                                 tp++;
3500                         }
3501                         pp = tp;
3502
3503                         if(clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
3504
3505                         /* cp is the next component to be created. */
3506                         code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
3507                         if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
3508                                 smb_NotifyChange(FILE_ACTION_ADDED,
3509                                 FILE_NOTIFY_CHANGE_DIR_NAME,
3510                                 tscp, cp, NULL, TRUE);
3511                         if (code == 0 || 
3512                                 (code == CM_ERROR_EXISTS && createDisp != 2)) {
3513                                         /* Not an exclusive create, and someone else tried
3514                                         * creating it already, then we open it anyway.  We
3515                                         * don't bother retrying after this, since if this next
3516                                         * fails, that means that the file was deleted after we
3517                                         * started this call.
3518                                         */
3519                                         code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
3520                                                 userp, &req, &scp);
3521                                 }
3522                         if(code) break;
3523
3524                         if(!isLast) { /* for anything other than dscp, release it unless it's the last one */
3525                                 cm_ReleaseSCache(tscp);
3526                                 tscp = scp; /* Newly created directory will be next parent */
3527                         }
3528                 }
3529
3530                 /* 
3531                 if we get here and code == 0, then scp is the last directory created, and tscp is the
3532                 parent of scp.  dscp got released if dscp != tscp. both tscp and scp are held.
3533                 */
3534                 dscp = tscp;
3535         }
3536
3537         if (code) {
3538                 /* something went wrong creating or truncating the file */
3539                 if (scp) cm_ReleaseSCache(scp);
3540         if (dscp) cm_ReleaseSCache(dscp);
3541                 cm_ReleaseUser(userp);
3542                 free(realPathp);
3543                 return code;
3544         }
3545
3546         /* make sure we have file vs. dir right (only applies for single component case) */
3547         if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3548                 cm_ReleaseSCache(scp);
3549         if (dscp) cm_ReleaseSCache(dscp);
3550                 cm_ReleaseUser(userp);
3551                 free(realPathp);
3552                 return CM_ERROR_ISDIR;
3553         }
3554     /* (only applies to single component case) */
3555         if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3556                 cm_ReleaseSCache(scp);
3557         if (dscp) cm_ReleaseSCache(dscp);
3558                 cm_ReleaseUser(userp);
3559                 free(realPathp);
3560                 return CM_ERROR_NOTDIR;
3561         }
3562
3563         /* open the file itself */
3564         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3565         osi_assert(fidp);
3566         /* save a pointer to the vnode */
3567         fidp->scp = scp;
3568
3569         fidp->flags = fidflags;
3570
3571         /* save parent dir and pathname for delete or change notification */
3572         if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3573                 fidp->flags |= SMB_FID_NTOPEN;
3574                 fidp->NTopen_dscp = dscp;
3575                 cm_HoldSCache(dscp);
3576                 fidp->NTopen_pathp = strdup(lastNamep);
3577         }
3578         fidp->NTopen_wholepathp = realPathp;
3579
3580         /* we don't need this any longer */
3581         if (dscp) cm_ReleaseSCache(dscp);
3582         cm_Open(scp, 0, userp);
3583
3584         /* set inp->fid so that later read calls in same msg can find fid */
3585         inp->fid = fidp->fid;
3586
3587         /* out parms */
3588         parmSlot = 2;
3589         lock_ObtainMutex(&scp->mx);
3590         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
3591         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3592         smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3593         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3594         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3595         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3596         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3597         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3598         smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3599                                                 parmSlot += 2;
3600         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3601         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3602         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
3603         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
3604         smb_SetSMBParmByte(outp, parmSlot,
3605                 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3606         lock_ReleaseMutex(&scp->mx);
3607         smb_SetSMBDataLength(outp, 0);
3608
3609         osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3610                  osi_LogSaveString(smb_logp, realPathp));
3611
3612         smb_ReleaseFID(fidp);
3613
3614         cm_ReleaseUser(userp);
3615
3616     /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
3617
3618         /* leave scp held since we put it in fidp->scp */
3619         return 0;
3620 }
3621
3622 /*
3623  * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3624  * Instead, ultimately, would like to use a subroutine for common code.
3625  */
3626 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3627 {
3628         char *pathp, *realPathp;
3629         long code = 0;
3630         cm_space_t *spacep;
3631         cm_user_t *userp;
3632         cm_scache_t *dscp;              /* parent dir */
3633         cm_scache_t *scp;               /* file to create or open */
3634         cm_attr_t setAttr;
3635         char *lastNamep;
3636         unsigned long nameLength;
3637         unsigned int flags;
3638         unsigned int requestOpLock;
3639         unsigned int requestBatchOpLock;
3640         unsigned int mustBeDir;
3641     unsigned int extendedRespRequired;
3642         int realDirFlag;
3643         unsigned int desiredAccess;
3644 #ifdef DEBUG_VERBOSE    
3645     unsigned int allocSize;
3646     unsigned int shareAccess;
3647 #endif
3648         unsigned int extAttributes;
3649         unsigned int createDisp;
3650 #ifdef DEBUG_VERBOSE
3651     unsigned int sdLen;
3652 #endif
3653         unsigned int createOptions;
3654         int initialModeBits;
3655         unsigned short baseFid;
3656         smb_fid_t *baseFidp;
3657         smb_fid_t *fidp;
3658         cm_scache_t *baseDirp;
3659         unsigned short openAction;
3660         int parmSlot;
3661         long fidflags;
3662         FILETIME ft;
3663         char *tidPathp;
3664         BOOL foundscp;
3665         int parmOffset, dataOffset;
3666         char *parmp;
3667         ULONG *lparmp;
3668         char *outData;
3669         cm_req_t req;
3670
3671         cm_InitReq(&req);
3672
3673         foundscp = FALSE;
3674         scp = NULL;
3675
3676         parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3677                         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3678         parmp = inp->data + parmOffset;
3679         lparmp = (ULONG *) parmp;
3680
3681         flags = lparmp[0];
3682         requestOpLock = flags & 0x02;
3683         requestBatchOpLock = flags & 0x04;
3684         mustBeDir = flags & 0x08;
3685     extendedRespRequired = flags & 0x10;
3686
3687         /*
3688          * Why all of a sudden 32-bit FID?
3689          * We will reject all bits higher than 16.
3690          */
3691         if (lparmp[1] & 0xFFFF0000)
3692                 return CM_ERROR_INVAL;
3693         baseFid = (unsigned short)lparmp[1];
3694         desiredAccess = lparmp[2];
3695 #ifdef DEBUG_VERBOSE
3696     allocSize = lparmp[3];
3697 #endif /* DEBUG_VERSOSE */
3698         extAttributes = lparmp[5];
3699 #ifdef DEBUG_VEROSE
3700     shareAccess = lparmp[6];
3701 #endif
3702         createDisp = lparmp[7];
3703         createOptions = lparmp[8];
3704 #ifdef DEBUG_VERBOSE
3705     sdLen = lparmp[9];
3706 #endif
3707         nameLength = lparmp[11];
3708
3709 #ifdef DEBUG_VERBOSE
3710         osi_Log4(smb_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
3711         osi_Log2(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
3712         osi_Log1(smb_logp,"... flags[%x]",flags);
3713 #endif
3714
3715         /* mustBeDir is never set; createOptions directory bit seems to be
3716          * more important
3717          */
3718         if (createOptions & 1)
3719                 realDirFlag = 1;
3720         else if (createOptions & 0x40)
3721                 realDirFlag = 0;
3722         else
3723                 realDirFlag = -1;
3724
3725         /*
3726          * compute initial mode bits based on read-only flag in
3727          * extended attributes
3728          */
3729         initialModeBits = 0666;
3730         if (extAttributes & 1) initialModeBits &= ~0222;
3731
3732         pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3733         /* Sometimes path is not null-terminated, so we make a copy. */
3734         realPathp = malloc(nameLength+1);
3735         memcpy(realPathp, pathp, nameLength);
3736         realPathp[nameLength] = 0;
3737
3738         spacep = cm_GetSpace();
3739         smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3740
3741         /*
3742          * Nothing here to handle SMB_IOCTL_FILENAME.
3743          * Will add it if necessary.
3744          */
3745
3746 #ifdef DEBUG_VERBOSE
3747         {
3748                 char *hexp, *asciip;
3749                 asciip = (lastNamep? lastNamep : realPathp);
3750                 hexp = osi_HexifyString( asciip );
3751                 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
3752                 free(hexp);
3753         }
3754 #endif
3755
3756         userp = smb_GetUser(vcp, inp);
3757     if(!userp) {
3758         osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
3759         free(realPathp);
3760         return CM_ERROR_INVAL;
3761     }
3762
3763         if (baseFid == 0) {
3764                 baseDirp = cm_rootSCachep;
3765                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3766         }
3767         else {
3768         baseFidp = smb_FindFID(vcp, baseFid, 0);
3769         if(!baseFidp) {
3770                 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
3771                 free(realPathp);
3772                 cm_ReleaseUser(userp);
3773                 return CM_ERROR_INVAL;
3774         }
3775                 baseDirp = baseFidp->scp;
3776                 tidPathp = NULL;
3777         }
3778
3779     /* compute open mode */
3780     fidflags = 0;
3781     if (desiredAccess & DELETE)
3782         fidflags |= SMB_FID_OPENDELETE;
3783     if (desiredAccess & AFS_ACCESS_READ)
3784         fidflags |= SMB_FID_OPENREAD;
3785     if (desiredAccess & AFS_ACCESS_WRITE)
3786         fidflags |= SMB_FID_OPENWRITE;
3787
3788         dscp = NULL;
3789         code = 0;
3790     if (createDisp == 2 || createDisp == 4) {
3791         code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3792                         userp, tidPathp, &req, &dscp);
3793         if (code == 0) {
3794             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
3795                              userp, tidPathp, &req, &scp);
3796         } else 
3797             dscp = NULL;
3798     } else {
3799         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3800                         userp, tidPathp, &req, &scp);
3801     }
3802
3803         if (code == 0) foundscp = TRUE;
3804         if (code != 0
3805             || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3806                 /* look up parent directory */
3807         if ( !dscp ) {
3808             code = cm_NameI(baseDirp, spacep->data,
3809                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3810                              userp, tidPathp, &req, &dscp);
3811         } else
3812             code = 0;
3813         
3814         cm_FreeSpace(spacep);
3815
3816                 if (baseFid != 0) {
3817            smb_ReleaseFID(baseFidp);
3818            baseFidp = 0;
3819         }
3820
3821                 if (code) {
3822                         cm_ReleaseUser(userp);
3823                         free(realPathp);
3824                         return code;
3825                 }
3826
3827                 if (!lastNamep) lastNamep = realPathp;
3828                 else lastNamep++;
3829
3830         if (!smb_IsLegalFilename(lastNamep))
3831             return CM_ERROR_BADNTFILENAME;
3832
3833                 if (!foundscp) {
3834             if (createDisp == 2 || createDisp == 4)
3835                 code = cm_Lookup(dscp, lastNamep,
3836                                  CM_FLAG_FOLLOW, userp, &req, &scp);
3837             else
3838                 code = cm_Lookup(dscp, lastNamep,
3839                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3840                                  userp, &req, &scp);
3841                         if (code && code != CM_ERROR_NOSUCHFILE) {
3842                                 cm_ReleaseSCache(dscp);
3843                                 cm_ReleaseUser(userp);
3844                                 free(realPathp);
3845                                 return code;
3846                         }
3847                 }
3848         }
3849         else {
3850                 if (baseFid != 0) {
3851             smb_ReleaseFID(baseFidp);
3852             baseFidp = 0;
3853         }
3854                 cm_FreeSpace(spacep);
3855         }
3856
3857         /* if we get here, if code is 0, the file exists and is represented by
3858          * scp.  Otherwise, we have to create it.  The dir may be represented
3859          * by dscp, or we may have found the file directly.  If code is non-zero,
3860          * scp is NULL.
3861          */
3862         if (code == 0) {
3863                 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3864                                       &req);
3865                 if (code) {
3866                         if (dscp) cm_ReleaseSCache(dscp);
3867                         cm_ReleaseSCache(scp);
3868                         cm_ReleaseUser(userp);
3869                         free(realPathp);
3870                         return code;
3871                 }
3872
3873                 if (createDisp == 2) {
3874                         /* oops, file shouldn't be there */
3875                         if (dscp) cm_ReleaseSCache(dscp);
3876                         cm_ReleaseSCache(scp);
3877                         cm_ReleaseUser(userp);
3878                         free(realPathp);
3879                         return CM_ERROR_EXISTS;
3880                 }
3881
3882                 if (createDisp == 4
3883                     || createDisp == 5) {
3884                         setAttr.mask = CM_ATTRMASK_LENGTH;
3885                         setAttr.length.LowPart = 0;
3886                         setAttr.length.HighPart = 0;
3887                         code = cm_SetAttr(scp, &setAttr, userp, &req);
3888                         openAction = 3; /* truncated existing file */
3889                 }
3890                 else openAction = 1;    /* found existing file */
3891         }
3892         else if (createDisp == 1 || createDisp == 4) {
3893                 /* don't create if not found */
3894                 if (dscp) cm_ReleaseSCache(dscp);
3895                 cm_ReleaseUser(userp);
3896                 free(realPathp);
3897                 return CM_ERROR_NOSUCHFILE;
3898         }
3899         else if (realDirFlag == 0 || realDirFlag == -1) {
3900                 osi_assert(dscp != NULL);
3901                 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
3902                  osi_LogSaveString(smb_logp, lastNamep));
3903                 openAction = 2;         /* created file */
3904                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3905                 setAttr.clientModTime = time(NULL);
3906                 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3907                                  &req);
3908                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3909                         smb_NotifyChange(FILE_ACTION_ADDED,
3910                                          FILE_NOTIFY_CHANGE_FILE_NAME,
3911                                          dscp, lastNamep, NULL, TRUE);
3912                 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3913                         /* Not an exclusive create, and someone else tried
3914                          * creating it already, then we open it anyway.  We
3915                          * don't bother retrying after this, since if this next
3916                          * fails, that means that the file was deleted after we
3917                          * started this call.
3918                          */
3919                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3920                                          userp, &req, &scp);
3921                         if (code == 0) {
3922                                 if (createDisp == 5) {
3923                                         setAttr.mask = CM_ATTRMASK_LENGTH;
3924                                         setAttr.length.LowPart = 0;
3925                                         setAttr.length.HighPart = 0;
3926                                         code = cm_SetAttr(scp, &setAttr, userp,
3927                                                           &req);
3928                                 }
3929                         }       /* lookup succeeded */
3930                 }
3931         }
3932         else {
3933                 /* create directory */
3934                 osi_assert(dscp != NULL);
3935                 osi_Log1(smb_logp,
3936                                 "smb_ReceiveNTTranCreate creating directory %s",
3937                                 osi_LogSaveString(smb_logp, lastNamep));
3938                 openAction = 2;         /* created directory */
3939                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3940                 setAttr.clientModTime = time(NULL);
3941                 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3942                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3943                         smb_NotifyChange(FILE_ACTION_ADDED,
3944                                          FILE_NOTIFY_CHANGE_DIR_NAME,
3945                                          dscp, lastNamep, NULL, TRUE);
3946                 if (code == 0
3947                     || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3948                         /* Not an exclusive create, and someone else tried
3949                          * creating it already, then we open it anyway.  We
3950                          * don't bother retrying after this, since if this next
3951                          * fails, that means that the file was deleted after we
3952                          * started this call.
3953                          */
3954                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3955                                          userp, &req, &scp);
3956                 }
3957         }
3958
3959         if (code) {
3960                 /* something went wrong creating or truncating the file */
3961                 if (scp) cm_ReleaseSCache(scp);
3962                 cm_ReleaseUser(userp);
3963                 free(realPathp);
3964                 return code;
3965         }
3966
3967         /* make sure we have file vs. dir right */
3968         if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3969                 cm_ReleaseSCache(scp);
3970                 cm_ReleaseUser(userp);
3971                 free(realPathp);
3972                 return CM_ERROR_ISDIR;
3973         }
3974         if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3975                 cm_ReleaseSCache(scp);
3976                 cm_ReleaseUser(userp);
3977                 free(realPathp);
3978                 return CM_ERROR_NOTDIR;
3979         }
3980
3981         /* open the file itself */
3982         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3983         osi_assert(fidp);
3984
3985         /* save a pointer to the vnode */
3986         fidp->scp = scp;
3987
3988         fidp->flags = fidflags;
3989
3990     /* save parent dir and pathname for deletion or change notification */
3991     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3992         fidp->flags |= SMB_FID_NTOPEN;
3993         fidp->NTopen_dscp = dscp;
3994         cm_HoldSCache(dscp);
3995         fidp->NTopen_pathp = strdup(lastNamep);
3996     }
3997         fidp->NTopen_wholepathp = realPathp;
3998
3999         /* we don't need this any longer */
4000         if (dscp) cm_ReleaseSCache(dscp);
4001
4002         cm_Open(scp, 0, userp);
4003
4004         /* set inp->fid so that later read calls in same msg can find fid */
4005         inp->fid = fidp->fid;
4006
4007     /* check whether we are required to send an extended response */
4008     if (!extendedRespRequired) {
4009         /* out parms */
4010         parmOffset = 8*4 + 39;
4011         parmOffset += 1;        /* pad to 4 */
4012         dataOffset = parmOffset + 70;
4013
4014         parmSlot = 1;
4015         outp->oddByte = 1;
4016         /* Total Parameter Count */
4017         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
4018         /* Total Data Count */
4019         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4020         /* Parameter Count */
4021         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
4022         /* Parameter Offset */
4023         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4024         /* Parameter Displacement */
4025         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4026         /* Data Count */
4027         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4028         /* Data Offset */
4029         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4030         /* Data Displacement */
4031         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4032         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
4033         smb_SetSMBDataLength(outp, 70);
4034
4035         lock_ObtainMutex(&scp->mx);
4036         outData = smb_GetSMBData(outp, NULL);
4037         outData++;                      /* round to get to parmOffset */
4038         *outData = 0; outData++;        /* oplock */
4039         *outData = 0; outData++;        /* reserved */
4040         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
4041         *((ULONG *)outData) = openAction; outData += 4;
4042         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
4043         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4044         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
4045         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
4046         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
4047         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
4048         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
4049         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
4050         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
4051         *((USHORT *)outData) = 0; outData += 2; /* filetype */
4052         *((USHORT *)outData) = 0; outData += 2; /* dev state */
4053         *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
4054         outData += 2;   /* is a dir? */
4055         lock_ReleaseMutex(&scp->mx);
4056     } else {
4057         /* out parms */
4058         parmOffset = 8*4 + 39;
4059         parmOffset += 1;        /* pad to 4 */
4060         dataOffset = parmOffset + 104;
4061         
4062         parmSlot = 1;
4063         outp->oddByte = 1;
4064         /* Total Parameter Count */
4065         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
4066         /* Total Data Count */
4067         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4068         /* Parameter Count */
4069         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
4070         /* Parameter Offset */
4071         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4072         /* Parameter Displacement */
4073         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4074         /* Data Count */
4075         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4076         /* Data Offset */
4077         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4078         /* Data Displacement */
4079         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4080         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
4081         smb_SetSMBDataLength(outp, 105);
4082         
4083         lock_ObtainMutex(&scp->mx);
4084         outData = smb_GetSMBData(outp, NULL);
4085         outData++;                      /* round to get to parmOffset */
4086         *outData = 0; outData++;        /* oplock */
4087         *outData = 1; outData++;        /* response type */
4088         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
4089         *((ULONG *)outData) = openAction; outData += 4;
4090         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
4091         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4092         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
4093         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
4094         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
4095         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
4096         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
4097         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
4098         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
4099         *((USHORT *)outData) = 0; outData += 2; /* filetype */
4100         *((USHORT *)outData) = 0; outData += 2; /* dev state */
4101         *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
4102         outData += 1;   /* is a dir? */
4103         memset(outData,0,24); outData += 24; /* Volume ID and file ID */
4104         *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
4105         *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
4106         lock_ReleaseMutex(&scp->mx);
4107     }
4108
4109         osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
4110
4111         smb_ReleaseFID(fidp);
4112
4113         cm_ReleaseUser(userp);
4114
4115         /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
4116         /* leave scp held since we put it in fidp->scp */
4117         return 0;
4118 }
4119
4120 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
4121         smb_packet_t *outp)
4122 {
4123         smb_packet_t *savedPacketp;
4124         ULONG filter; USHORT fid, watchtree;
4125         smb_fid_t *fidp;
4126         cm_scache_t *scp;
4127         
4128         filter = smb_GetSMBParm(inp, 19)
4129                         | (smb_GetSMBParm(inp, 20) << 16);
4130         fid = smb_GetSMBParm(inp, 21);
4131         watchtree = smb_GetSMBParm(inp, 22) && 0xffff;  /* TODO: should this be 0xff ? */
4132
4133     fidp = smb_FindFID(vcp, fid, 0);
4134     if (!fidp) {
4135         osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
4136         return CM_ERROR_BADFD;
4137     }
4138
4139         savedPacketp = smb_CopyPacket(inp);
4140         savedPacketp->vcp = vcp; /* TODO: refcount vcp? */
4141         lock_ObtainMutex(&smb_Dir_Watch_Lock);
4142         savedPacketp->nextp = smb_Directory_Watches;
4143         smb_Directory_Watches = savedPacketp;
4144         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4145
4146     osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
4147              filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
4148
4149     scp = fidp->scp;
4150     lock_ObtainMutex(&scp->mx);
4151     if (watchtree)
4152         scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
4153     else
4154         scp->flags |= CM_SCACHEFLAG_WATCHED;
4155     lock_ReleaseMutex(&scp->mx);
4156     smb_ReleaseFID(fidp);
4157
4158         outp->flags |= SMB_PACKETFLAG_NOSEND;
4159         return 0;
4160 }
4161
4162 unsigned char nullSecurityDesc[36] = {
4163         0x01,                           /* security descriptor revision */
4164         0x00,                           /* reserved, should be zero */
4165         0x00, 0x80,                     /* security descriptor control;
4166                                          * 0x8000 : self-relative format */
4167         0x14, 0x00, 0x00, 0x00,         /* offset of owner SID */
4168         0x1c, 0x00, 0x00, 0x00,         /* offset of group SID */
4169         0x00, 0x00, 0x00, 0x00,         /* offset of DACL would go here */
4170         0x00, 0x00, 0x00, 0x00,         /* offset of SACL would go here */
4171         0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4172                                         /* "null SID" owner SID */
4173         0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4174                                         /* "null SID" group SID */
4175 };
4176
4177 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4178 {
4179         int parmOffset, parmCount, dataOffset, dataCount;
4180         int parmSlot;
4181         int maxData;
4182         char *outData;
4183         char *parmp;
4184         USHORT *sparmp;
4185         ULONG *lparmp;
4186         USHORT fid;
4187         ULONG securityInformation;
4188
4189         parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
4190                         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
4191         parmp = inp->data + parmOffset;
4192         sparmp = (USHORT *) parmp;
4193         lparmp = (ULONG *) parmp;
4194
4195         fid = sparmp[0];
4196         securityInformation = lparmp[1];
4197
4198         maxData = smb_GetSMBOffsetParm(inp, 7, 1)
4199                         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4200
4201         if (maxData < 36)
4202                 dataCount = 0;
4203         else
4204                 dataCount = 36;
4205
4206         /* out parms */
4207         parmOffset = 8*4 + 39;
4208         parmOffset += 1;        /* pad to 4 */
4209         parmCount = 4;
4210         dataOffset = parmOffset + parmCount;
4211
4212         parmSlot = 1;
4213         outp->oddByte = 1;
4214         /* Total Parameter Count */
4215         smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
4216         /* Total Data Count */
4217         smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
4218         /* Parameter Count */
4219         smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
4220         /* Parameter Offset */
4221         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4222         /* Parameter Displacement */
4223         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4224         /* Data Count */
4225         smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
4226         /* Data Offset */
4227         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4228         /* Data Displacement */
4229         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4230         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
4231         smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
4232
4233         outData = smb_GetSMBData(outp, NULL);
4234         outData++;                      /* round to get to parmOffset */
4235         *((ULONG *)outData) = 36; outData += 4; /* length */
4236
4237         if (maxData >= 36) {
4238                 memcpy(outData, nullSecurityDesc, 36);
4239                 outData += 36;
4240                 return 0;
4241         } else
4242                 return CM_ERROR_BUFFERTOOSMALL;
4243 }
4244
4245 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4246 {
4247         unsigned short function;
4248
4249         function = smb_GetSMBParm(inp, 18);
4250
4251         osi_Log1(smb_logp, "SMB NT Transact function %d", function);
4252
4253         /* We can handle long names */
4254         if (vcp->flags & SMB_VCFLAG_USENT)
4255                 ((smb_t *)outp)->flg2 |= 0x40;  /* IS_LONG_NAME */
4256         
4257         switch (function) {
4258
4259                 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
4260
4261                 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
4262
4263                 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
4264
4265                 default: return CM_ERROR_INVAL;
4266         }
4267 }
4268
4269 /*
4270  * smb_NotifyChange -- find relevant change notification messages and
4271  *                     reply to them
4272  *
4273  * If we don't know the file name (i.e. a callback break), filename is
4274  * NULL, and we return a zero-length list.
4275  */
4276 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
4277         cm_scache_t *dscp, char *filename, char *otherFilename,
4278         BOOL isDirectParent)
4279 {
4280         smb_packet_t *watch, *lastWatch, *nextWatch;
4281         ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
4282         char *outData, *oldOutData;
4283         ULONG filter;
4284         USHORT fid, wtree;
4285         ULONG maxLen;
4286         BOOL twoEntries = FALSE;
4287         ULONG otherNameLen, oldParmCount = 0;
4288         DWORD otherAction;
4289         smb_vc_t *vcp;
4290         smb_fid_t *fidp;
4291
4292         /* Get ready for rename within directory */
4293         if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
4294                 twoEntries = TRUE;
4295                 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
4296         }
4297
4298         lock_ObtainMutex(&smb_Dir_Watch_Lock);
4299         watch = smb_Directory_Watches;
4300         while (watch) {
4301                 filter = smb_GetSMBParm(watch, 19)
4302                                 | (smb_GetSMBParm(watch, 20) << 16);
4303                 fid = smb_GetSMBParm(watch, 21);
4304                 wtree = smb_GetSMBParm(watch, 22) & 0xffff;  /* TODO: should this be 0xff ? */
4305                 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
4306                                 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
4307                 vcp = watch->vcp;
4308
4309                 /*
4310                  * Strange hack - bug in NT Client and NT Server that we
4311                  * must emulate?
4312                  */
4313                 if (filter == 3 && wtree)
4314                         filter = 0x17;
4315
4316                 fidp = smb_FindFID(vcp, fid, 0);
4317         if (!fidp) {
4318                 lastWatch = watch;
4319                 watch = watch->nextp;
4320                 continue;
4321         }
4322                 if (fidp->scp != dscp
4323                     || (filter & notifyFilter) == 0
4324                     || (!isDirectParent && !wtree)) {
4325                         smb_ReleaseFID(fidp);
4326                         lastWatch = watch;
4327                         watch = watch->nextp;
4328                         continue;
4329                 }
4330                 smb_ReleaseFID(fidp);
4331
4332                 osi_Log4(smb_logp,
4333                          "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
4334                          fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
4335
4336                 nextWatch = watch->nextp;
4337                 if (watch == smb_Directory_Watches)
4338                         smb_Directory_Watches = nextWatch;
4339                 else
4340                         lastWatch->nextp = nextWatch;
4341
4342                 /* Turn off WATCHED flag in dscp */
4343                 lock_ObtainMutex(&dscp->mx);
4344                 if (wtree)
4345                         dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4346                 else
4347                         dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
4348                 lock_ReleaseMutex(&dscp->mx);
4349
4350                 /* Convert to response packet */
4351                 ((smb_t *) watch)->reb = 0x80;
4352                 ((smb_t *) watch)->wct = 0;
4353
4354                 /* out parms */
4355                 if (filename == NULL)
4356                         parmCount = 0;
4357                 else {
4358                         nameLen = strlen(filename);
4359                         parmCount = 3*4 + nameLen*2;
4360                         parmCount = (parmCount + 3) & ~3;       /* pad to 4 */
4361                         if (twoEntries) {
4362                                 otherNameLen = strlen(otherFilename);
4363                                 oldParmCount = parmCount;
4364                                 parmCount += 3*4 + otherNameLen*2;
4365                                 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
4366                         }
4367                         if (maxLen < parmCount)
4368                                 parmCount = 0;  /* not enough room */
4369                 }
4370                 parmOffset = 8*4 + 39;
4371                 parmOffset += 1;                        /* pad to 4 */
4372                 dataOffset = parmOffset + parmCount;
4373
4374                 parmSlot = 1;
4375                 watch->oddByte = 1;
4376                 /* Total Parameter Count */
4377                 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4378                 /* Total Data Count */
4379                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4380                 /* Parameter Count */
4381                 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4382                 /* Parameter Offset */
4383                 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
4384                 /* Parameter Displacement */
4385                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4386                 /* Data Count */
4387                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4388                 /* Data Offset */
4389                 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
4390                 /* Data Displacement */
4391                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4392                 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
4393                 smb_SetSMBDataLength(watch, parmCount + 1);
4394
4395                 if (parmCount != 0) {
4396                         outData = smb_GetSMBData(watch, NULL);
4397                         outData++;      /* round to get to parmOffset */
4398                         oldOutData = outData;
4399                         *((DWORD *)outData) = oldParmCount; outData += 4;
4400                                         /* Next Entry Offset */
4401                         *((DWORD *)outData) = action; outData += 4;
4402                                         /* Action */
4403                         *((DWORD *)outData) = nameLen*2; outData += 4;
4404                                         /* File Name Length */
4405                         mbstowcs((WCHAR *)outData, filename, nameLen);
4406                                         /* File Name */
4407                         if (twoEntries) {
4408                                 outData = oldOutData + oldParmCount;
4409                                 *((DWORD *)outData) = 0; outData += 4;
4410                                         /* Next Entry Offset */
4411                                 *((DWORD *)outData) = otherAction; outData += 4;
4412                                         /* Action */
4413                                 *((DWORD *)outData) = otherNameLen*2;
4414                                 outData += 4;   /* File Name Length */
4415                                 mbstowcs((WCHAR *)outData, otherFilename,
4416                                          otherNameLen); /* File Name */
4417                         }
4418                 }
4419
4420                 /*
4421                  * If filename is null, we don't know the cause of the
4422                  * change notification.  We return zero data (see above),
4423                  * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
4424                  * (= 0x010C).  We set the error code here by hand, without
4425                  * modifying wct and bcc.
4426                  */
4427                 if (filename == NULL) {
4428                         ((smb_t *) watch)->rcls = 0x0C;
4429                         ((smb_t *) watch)->reh = 0x01;
4430                         ((smb_t *) watch)->errLow = 0;
4431                         ((smb_t *) watch)->errHigh = 0;
4432                         /* Set NT Status codes flag */
4433                         ((smb_t *) watch)->flg2 |= 0x4000;
4434                 }
4435
4436                 smb_SendPacket(vcp, watch);
4437                 smb_FreePacket(watch);
4438                 watch = nextWatch;
4439         }
4440         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4441 }
4442
4443 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4444 {
4445         unsigned char *replyWctp;
4446         smb_packet_t *watch, *lastWatch;
4447         USHORT fid, watchtree;
4448         smb_fid_t *fidp;
4449         cm_scache_t *scp;
4450
4451         osi_Log0(smb_logp, "SMB3 receive NT cancel");
4452
4453         lock_ObtainMutex(&smb_Dir_Watch_Lock);
4454         watch = smb_Directory_Watches;
4455         while (watch) {
4456                 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
4457                     && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
4458                     && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
4459                     && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
4460                         if (watch == smb_Directory_Watches)
4461                                 smb_Directory_Watches = watch->nextp;
4462                         else
4463                                 lastWatch->nextp = watch->nextp;
4464                         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4465
4466                         /* Turn off WATCHED flag in scp */
4467                         fid = smb_GetSMBParm(watch, 21);
4468                         watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
4469
4470                         fidp = smb_FindFID(vcp, fid, 0);
4471             if (fidp) {
4472                 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s", 
4473                          fid, watchtree,
4474                          osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
4475
4476                 scp = fidp->scp;
4477                 lock_ObtainMutex(&scp->mx);
4478                 if (watchtree)
4479                     scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4480                 else
4481                     scp->flags &= ~CM_SCACHEFLAG_WATCHED;
4482                 lock_ReleaseMutex(&scp->mx);
4483                 smb_ReleaseFID(fidp);
4484             } else {
4485                 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
4486             }
4487
4488                         /* assume STATUS32; return 0xC0000120 (CANCELED) */
4489                         replyWctp = watch->wctp;
4490                         *replyWctp++ = 0;
4491                         *replyWctp++ = 0;
4492                         *replyWctp++ = 0;
4493                         ((smb_t *)watch)->rcls = 0x20;
4494                         ((smb_t *)watch)->reh = 0x1;
4495                         ((smb_t *)watch)->errLow = 0;
4496                         ((smb_t *)watch)->errHigh = 0xC0;
4497                         ((smb_t *)watch)->flg2 |= 0x4000;
4498                         smb_SendPacket(vcp, watch);
4499                         smb_FreePacket(watch);
4500                         return 0;
4501                 }
4502                 lastWatch = watch;
4503                 watch = watch->nextp;
4504         }
4505         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4506
4507         return 0;
4508 }
4509
4510 void smb3_Init()
4511 {
4512         lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
4513 }
4514
4515 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
4516 {
4517     /*int newUid;*/
4518     smb_username_t *unp;
4519
4520     unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
4521     if (!unp->userp) {
4522         lock_ObtainMutex(&unp->mx);
4523         unp->userp = cm_NewUser();
4524         lock_ReleaseMutex(&unp->mx);
4525                 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
4526     }  else     {
4527                 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);
4528         }
4529     return unp->userp;
4530 }
4531