9172455d425b3961c022fdb47f2cdcb4505a2b59
[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 #ifndef USE_OLD_MATCHING
1749 // char table for case insensitive comparison
1750 char mapCaseTable[256];
1751
1752 VOID initUpperCaseTable(VOID) 
1753 {
1754     int i;
1755     for (i = 0; i < 256; ++i) 
1756        mapCaseTable[i] = toupper(i);
1757     // make '"' match '.' 
1758     mapCaseTable[(int)'"'] = toupper('.');
1759 }
1760
1761 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
1762 // name 'name'.
1763 // Note : this procedure works recursively calling itself.
1764 // Parameters
1765 // PSZ pattern    : string containing metacharacters.
1766 // PSZ name       : file name to be compared with 'pattern'.
1767 // Return value
1768 // BOOL : TRUE/FALSE (match/mistmatch)
1769
1770 BOOL szWildCardMatchFileName(PSZ pattern, PSZ name) {
1771    PSZ pename;         // points to the last 'name' character
1772    PSZ p;
1773    pename = name + strlen(name) - 1;
1774    while (*name) {
1775       switch (*pattern) {
1776          case '?':
1777             if (*(++pattern) != '<' || *(++pattern) != '*') {
1778                if (*name == '.') return FALSE;
1779                ++name;
1780                break;
1781             } /* endif */
1782          case '<':
1783          case '*':
1784             while ((*pattern == '<') || (*pattern == '*') || (*pattern == '?')) ++pattern;
1785             if (!*pattern) return TRUE;
1786             for (p = pename; p >= name; --p) {
1787                if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
1788                    szWildCardMatchFileName(pattern + 1, p + 1))
1789                   return TRUE;
1790             } /* endfor */
1791             return FALSE;
1792          default:
1793             if (mapCaseTable[*name] != mapCaseTable[*pattern]) return FALSE;
1794             ++pattern, ++name;
1795             break;
1796       } /* endswitch */
1797    } /* endwhile */ return !*pattern;
1798 }
1799
1800 /* do a case-folding search of the star name mask with the name in namep.
1801  * Return 1 if we match, otherwise 0.
1802  */
1803 int smb_V3MatchMask(char *namep, char *maskp, int flags) 
1804 {
1805         /* make sure we only match 8.3 names, if requested */
1806         if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
1807         return 0;
1808         
1809         return szWildCardMatchFileName(maskp, namep) ? 1:0;
1810 }
1811
1812 #else /* USE_OLD_MATCHING */
1813 /* do a case-folding search of the star name mask with the name in namep.
1814  * Return 1 if we match, otherwise 0.
1815  */
1816 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1817 {
1818         unsigned char tcp1, tcp2;       /* Pattern characters */
1819     unsigned char tcn1;         /* Name characters */
1820         int sawDot = 0, sawStar = 0, req8dot3 = 0;
1821         char *starNamep, *starMaskp;
1822         static char nullCharp[] = {0};
1823     int casefold = flags & CM_FLAG_CASEFOLD;
1824
1825         /* make sure we only match 8.3 names, if requested */
1826     req8dot3 = (flags & CM_FLAG_8DOT3);
1827         if (req8dot3 && !cm_Is8Dot3(namep)) 
1828         return 0;
1829
1830         /* loop */
1831         while (1) {
1832                 /* Next pattern character */
1833                 tcp1 = *maskp++;
1834
1835                 /* Next name character */
1836                 tcn1 = *namep;
1837
1838                 if (tcp1 == 0) {
1839                         /* 0 - end of pattern */
1840                         if (tcn1 == 0)
1841                                 return 1;
1842                         else
1843                                 return 0;
1844                 }
1845                 else if (tcp1 == '.' || tcp1 == '"') {
1846                         if (sawDot) {
1847                                 if (tcn1 == '.') {
1848                                         namep++;
1849                                         continue;
1850                                 } else
1851                                         return 0;
1852                         }
1853                         else {
1854                                 /*
1855                                  * first dot in pattern;
1856                                  * must match dot or end of name
1857                                  */
1858                                 sawDot = 1;
1859                                 if (tcn1 == 0)
1860                                         continue;
1861                                 else if (tcn1 == '.') {
1862                                         sawStar = 0;
1863                                         namep++;
1864                                         continue;
1865                                 }
1866                                 else
1867                                         return 0;
1868                         }
1869                 }
1870                 else if (tcp1 == '?') {
1871                         if (tcn1 == 0 || tcn1 == '.')
1872                                 return 0;
1873                         namep++;
1874                         continue;
1875                 }
1876                 else if (tcp1 == '>') {
1877                         if (tcn1 != 0 && tcn1 != '.')
1878                                 namep++;
1879                         continue;
1880                 }
1881                 else if (tcp1 == '*' || tcp1 == '<') {
1882                         tcp2 = *maskp++;
1883                         if (tcp2 == 0)
1884                                 return 1;
1885                         else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
1886                                 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
1887                                         tcn1 = *++namep;
1888                                 if (tcn1 == 0) {
1889                                         if (sawDot)
1890                                                 return 0;
1891                                         else
1892                                                 continue;
1893                                 }
1894                                 else {
1895                                         namep++;
1896                                         continue;
1897                                 }
1898                         }
1899                         else {
1900                                 /*
1901                                  * pattern character after '*' is not null or
1902                                  * period.  If it is '?' or '>', we are not
1903                                  * going to understand it.  If it is '*' or
1904                                  * '<', we are going to skip over it.  None of
1905                                  * these are likely, I hope.
1906                                  */
1907                                 /* skip over '*' and '<' */
1908                                 while (tcp2 == '*' || tcp2 == '<')
1909                                         tcp2 = *maskp++;
1910
1911                                 /* skip over characters that don't match tcp2 */
1912                                 while (req8dot3 && tcn1 != '.' && tcn1 != 0 && 
1913                        ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) || 
1914                          (!casefold && tcn1 != tcp2)))
1915                                         tcn1 = *++namep;
1916
1917                                 /* No match */
1918                                 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
1919                                         return 0;
1920
1921                                 /* Remember where we are */
1922                                 sawStar = 1;
1923                                 starMaskp = maskp;
1924                                 starNamep = namep;
1925
1926                                 namep++;
1927                                 continue;
1928                         }
1929                 }
1930                 else {
1931                         /* tcp1 is not a wildcard */
1932             if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) || 
1933                 (!casefold && tcn1 == tcp1)) {
1934                                 /* they match */
1935                                 namep++;
1936                                 continue;
1937                         }
1938                         /* if trying to match a star pattern, go back */
1939                         if (sawStar) {
1940                                 maskp = starMaskp - 2;
1941                                 namep = starNamep + 1;
1942                                 sawStar = 0;
1943                                 continue;
1944                         }
1945                         /* that's all */
1946                         return 0;
1947                 }
1948         }
1949 }
1950 #endif /* USE_OLD_MATCHING */
1951
1952 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1953 {
1954         int attribute;
1955     long nextCookie;
1956     char *tp;
1957     long code = 0;
1958     char *pathp;
1959     cm_dirEntry_t *dep;
1960     int maxCount;
1961     smb_dirListPatch_t *dirListPatchesp;
1962     smb_dirListPatch_t *curPatchp;
1963     cm_buf_t *bufferp;
1964     long temp;
1965     long orbytes;                       /* # of bytes in this output record */
1966     long ohbytes;                       /* # of bytes, except file name */
1967     long onbytes;                       /* # of bytes in name, incl. term. null */
1968     osi_hyper_t dirLength;
1969     osi_hyper_t bufferOffset;
1970     osi_hyper_t curOffset;
1971     osi_hyper_t thyper;
1972     smb_dirSearch_t *dsp;
1973     cm_scache_t *scp;
1974     long entryInDir;
1975     long entryInBuffer;
1976         cm_pageHeader_t *pageHeaderp;
1977     cm_user_t *userp = NULL;
1978     int slotInPage;
1979     int returnedNames;
1980     long nextEntryCookie;
1981     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
1982     char *op;                   /* output data ptr */
1983         char *origOp;                   /* original value of op */
1984     cm_space_t *spacep;         /* for pathname buffer */
1985     long maxReturnData;         /* max # of return data */
1986     long maxReturnParms;                /* max # of return parms */
1987     long bytesInBuffer;         /* # data bytes in the output buffer */
1988     int starPattern;
1989     char *maskp;                        /* mask part of path */
1990     int infoLevel;
1991     int searchFlags;
1992     int eos;
1993     smb_tran2Packet_t *outp;    /* response packet */
1994         char *tidPathp;
1995         int align;
1996         char shortName[13];             /* 8.3 name if needed */
1997         int NeedShortName;
1998     int foundInexact;
1999         char *shortNameEnd;
2000     int fileType;
2001     cm_fid_t fid;
2002
2003     cm_req_t req;
2004
2005         cm_InitReq(&req);
2006
2007         eos = 0;
2008         if (p->opcode == 1) {
2009                 /* find first; obtain basic parameters from request */
2010         attribute = p->parmsp[0];
2011         maxCount = p->parmsp[1];
2012         infoLevel = p->parmsp[3];
2013         searchFlags = p->parmsp[2];
2014         dsp = smb_NewDirSearch(1);
2015         dsp->attribute = attribute;
2016         pathp = ((char *) p->parmsp) + 12;      /* points to path */
2017         nextCookie = 0;
2018         maskp = strrchr(pathp, '\\');
2019         if (maskp == NULL) maskp = pathp;
2020                 else maskp++;   /* skip over backslash */
2021         strcpy(dsp->mask, maskp);       /* and save mask */
2022                 /* track if this is likely to match a lot of entries */
2023         starPattern = smb_V3IsStarMask(maskp);
2024         }
2025     else {
2026                 osi_assert(p->opcode == 2);
2027         /* find next; obtain basic parameters from request or open dir file */
2028         dsp = smb_FindDirSearch(p->parmsp[0]);
2029         if (!dsp) return CM_ERROR_BADFD;
2030         attribute = dsp->attribute;
2031         maxCount = p->parmsp[1];
2032         infoLevel = p->parmsp[2];
2033         searchFlags = p->parmsp[5];
2034         pathp = NULL;
2035         nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
2036         maskp = dsp->mask;
2037                 starPattern = 1;        /* assume, since required a Find Next */
2038     }
2039
2040         osi_Log4(smb_logp,
2041               "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
2042               attribute, infoLevel, maxCount, searchFlags);
2043
2044         osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
2045               p->opcode, nextCookie);
2046
2047         if (infoLevel >= 0x101)
2048                 searchFlags &= ~4;      /* no resume keys */
2049
2050     dirListPatchesp = NULL;
2051
2052         maxReturnData = p->maxReturnData;
2053     if (p->opcode == 1) /* find first */
2054         maxReturnParms = 10;    /* bytes */
2055         else    
2056         maxReturnParms = 8;     /* bytes */
2057
2058 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
2059     if (maxReturnData > 6000) 
2060         maxReturnData = 6000;
2061 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
2062
2063         outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
2064                                       maxReturnData);
2065
2066     osi_Log1(smb_logp, "T2 receive search dir %s",
2067              osi_LogSaveString(smb_logp, pathp));
2068         
2069     /* bail out if request looks bad */
2070     if (p->opcode == 1 && !pathp) {
2071         smb_ReleaseDirSearch(dsp);
2072         smb_FreeTran2Packet(outp);
2073         return CM_ERROR_BADSMB;
2074     }
2075         
2076         osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
2077              nextCookie, dsp->cookie);
2078
2079         userp = smb_GetTran2User(vcp, p);
2080     if (!userp) {
2081         osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
2082         smb_ReleaseDirSearch(dsp);
2083         smb_FreeTran2Packet(outp);
2084         return CM_ERROR_BADSMB;
2085     }
2086
2087         /* try to get the vnode for the path name next */
2088         lock_ObtainMutex(&dsp->mx);
2089         if (dsp->scp) {
2090                 scp = dsp->scp;
2091         cm_HoldSCache(scp);
2092         code = 0;
2093     }
2094     else {
2095                 spacep = cm_GetSpace();
2096         smb_StripLastComponent(spacep->data, NULL, pathp);
2097         lock_ReleaseMutex(&dsp->mx);
2098
2099                 tidPathp = smb_GetTIDPath(vcp, p->tid);
2100         code = cm_NameI(cm_rootSCachep, spacep->data,
2101                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2102                         userp, tidPathp, &req, &scp);
2103         cm_FreeSpace(spacep);
2104
2105         lock_ObtainMutex(&dsp->mx);
2106                 if (code == 0) {
2107             if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2108                         dsp->scp = scp;
2109                         /* we need one hold for the entry we just stored into,
2110              * and one for our own processing.  When we're done
2111                          * with this function, we'll drop the one for our own
2112                          * processing.  We held it once from the namei call,
2113                          * and so we do another hold now.
2114              */
2115             cm_HoldSCache(scp);
2116                         lock_ObtainMutex(&scp->mx);
2117                         if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2118                             && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2119                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2120                                 dsp->flags |= SMB_DIRSEARCH_BULKST;
2121                         }
2122                         lock_ReleaseMutex(&scp->mx);
2123         }
2124     }
2125         lock_ReleaseMutex(&dsp->mx);
2126     if (code) {
2127                 cm_ReleaseUser(userp);
2128         smb_FreeTran2Packet(outp);
2129                 smb_DeleteDirSearch(dsp);
2130                 smb_ReleaseDirSearch(dsp);
2131         return code;
2132         }
2133
2134     /* get the directory size */
2135         lock_ObtainMutex(&scp->mx);
2136     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2137                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2138         if (code) {
2139                 lock_ReleaseMutex(&scp->mx);
2140         cm_ReleaseSCache(scp);
2141         cm_ReleaseUser(userp);
2142         smb_FreeTran2Packet(outp);
2143                 smb_DeleteDirSearch(dsp);
2144                 smb_ReleaseDirSearch(dsp);
2145         return code;
2146     }
2147
2148   startsearch:
2149     dirLength = scp->length;
2150     bufferp = NULL;
2151     bufferOffset.LowPart = bufferOffset.HighPart = 0;
2152     curOffset.HighPart = 0;
2153     curOffset.LowPart = nextCookie;
2154         origOp = outp->datap;
2155
2156     foundInexact = 0;
2157     code = 0;
2158     returnedNames = 0;
2159     bytesInBuffer = 0;
2160     while (1) {
2161                 op = origOp;
2162                 if (searchFlags & 4)
2163                         /* skip over resume key */
2164                         op += 4;
2165
2166                 /* make sure that curOffset.LowPart doesn't point to the first
2167          * 32 bytes in the 2nd through last dir page, and that it doesn't
2168          * point at the first 13 32-byte chunks in the first dir page,
2169          * since those are dir and page headers, and don't contain useful
2170          * information.
2171          */
2172                 temp = curOffset.LowPart & (2048-1);
2173         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2174                         /* we're in the first page */
2175             if (temp < 13*32) temp = 13*32;
2176                 }
2177                 else {
2178                         /* we're in a later dir page */
2179             if (temp < 32) temp = 32;
2180         }
2181                 
2182         /* make sure the low order 5 bits are zero */
2183         temp &= ~(32-1);
2184                 
2185         /* now put temp bits back ito curOffset.LowPart */
2186         curOffset.LowPart &= ~(2048-1);
2187         curOffset.LowPart |= temp;
2188
2189         /* check if we've passed the dir's EOF */
2190         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2191             eos = 1;
2192             break;
2193         }
2194
2195         /* check if we've returned all the names that will fit in the
2196          * response packet; we check return count as well as the number
2197          * of bytes requested.  We check the # of bytes after we find
2198          * the dir entry, since we'll need to check its size.
2199          */
2200         if (returnedNames >= maxCount) {
2201             break;
2202         }
2203
2204         /* see if we can use the bufferp we have now; compute in which
2205          * page the current offset would be, and check whether that's
2206          * the offset of the buffer we have.  If not, get the buffer.
2207          */
2208         thyper.HighPart = curOffset.HighPart;
2209         thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2210         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2211                         /* wrong buffer */
2212             if (bufferp) {
2213                 buf_Release(bufferp);
2214                 bufferp = NULL;
2215                         }       
2216                         lock_ReleaseMutex(&scp->mx);
2217                         lock_ObtainRead(&scp->bufCreateLock);
2218             code = buf_Get(scp, &thyper, &bufferp);
2219                         lock_ReleaseRead(&scp->bufCreateLock);
2220
2221                         /* now, if we're doing a star match, do bulk fetching
2222                          * of all of the status info for files in the dir.
2223              */
2224             if (starPattern) {
2225                                 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2226                                           infoLevel, userp,
2227                                           &req);
2228                                 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2229                     && LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
2230                                         /* Don't bulk stat if risking timeout */
2231                                         int now = GetCurrentTime();
2232                                         if (now - req.startTime > 5000) {
2233                                                 scp->bulkStatProgress = thyper;
2234                                                 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2235                                                 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2236                                         } else
2237                         cm_TryBulkStat(scp, &thyper, userp, &req);
2238                                 }
2239                         }
2240
2241             lock_ObtainMutex(&scp->mx);
2242             if (code) break;
2243             bufferOffset = thyper;
2244
2245             /* now get the data in the cache */
2246             while (1) {
2247                                 code = cm_SyncOp(scp, bufferp, userp, &req,
2248                                  PRSFS_LOOKUP,
2249                                  CM_SCACHESYNC_NEEDCALLBACK
2250                                  | CM_SCACHESYNC_READ);
2251                                 if (code) break;
2252                                 
2253                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2254
2255                 /* otherwise, load the buffer and try again */
2256                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2257                                     &req);
2258                 if (code) break;
2259             }
2260             if (code) {
2261                                 buf_Release(bufferp);
2262                 bufferp = NULL;
2263                 break;
2264                         }
2265         }       /* if (wrong buffer) ... */
2266                 
2267         /* now we have the buffer containing the entry we're interested
2268          * in; copy it out if it represents a non-deleted entry.
2269          */
2270                 entryInDir = curOffset.LowPart & (2048-1);
2271         entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2272
2273                 /* page header will help tell us which entries are free.  Page
2274                  * header can change more often than once per buffer, since
2275                  * AFS 3 dir page size may be less than (but not more than)
2276                  * a buffer package buffer.
2277          */
2278                 /* only look intra-buffer */
2279                 temp = curOffset.LowPart & (buf_bufferSize - 1);
2280         temp &= ~(2048 - 1);    /* turn off intra-page bits */
2281                 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2282
2283                 /* now determine which entry we're looking at in the page.
2284                  * If it is free (there's a free bitmap at the start of the
2285                  * dir), we should skip these 32 bytes.
2286          */
2287         slotInPage = (entryInDir & 0x7e0) >> 5;
2288         if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2289                & (1 << (slotInPage & 0x7)))) {
2290                         /* this entry is free */
2291             numDirChunks = 1;   /* only skip this guy */
2292             goto nextEntry;
2293         }
2294
2295                 tp = bufferp->datap + entryInBuffer;
2296         dep = (cm_dirEntry_t *) tp;     /* now points to AFS3 dir entry */
2297
2298         /* while we're here, compute the next entry's location, too,
2299                  * since we'll need it when writing out the cookie into the dir
2300                  * listing stream.
2301          *
2302          * XXXX Probably should do more sanity checking.
2303          */
2304                 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2305                 
2306         /* compute offset of cookie representing next entry */
2307         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
2308
2309                 /* Need 8.3 name? */
2310                 NeedShortName = 0;
2311                 if (infoLevel == 0x104
2312                     && dep->fid.vnode != 0
2313                     && !cm_Is8Dot3(dep->name)) {
2314                         cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2315                         NeedShortName = 1;
2316                 }
2317
2318         /* When matching, we are using doing a case fold if we have a wildcard mask.
2319          * If we get a non-wildcard match, it's a lookup for a specific file. 
2320          */
2321         if (dep->fid.vnode != 0 && 
2322             (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0))
2323               || (NeedShortName
2324                    && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
2325
2326             /* Eliminate entries that don't match requested attributes */
2327             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && 
2328                  smb_IsDotFile(dep->name))
2329                 goto nextEntry; /* no hidden files */
2330                     
2331             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
2332             {
2333                 /* We have already done the cm_TryBulkStat above */
2334                 fid.cell = scp->fid.cell;
2335                 fid.volume = scp->fid.volume;
2336                 fid.vnode = ntohl(dep->fid.vnode);
2337                 fid.unique = ntohl(dep->fid.unique);
2338                 fileType = cm_FindFileType(&fid);
2339                 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
2340                  "has filetype %d", dep->name,
2341                  fileType);*/
2342                 if (fileType == CM_SCACHETYPE_DIRECTORY)
2343                     goto nextEntry;
2344             }
2345
2346                         /* finally check if this name will fit */
2347
2348                         /* standard dir entry stuff */
2349                         if (infoLevel < 0x101)
2350                                 ohbytes = 23;   /* pre-NT */
2351                         else if (infoLevel == 0x103)
2352                                 ohbytes = 12;   /* NT names only */
2353                         else
2354                                 ohbytes = 64;   /* NT */
2355
2356                         if (infoLevel == 0x104)
2357                                 ohbytes += 26;  /* Short name & length */
2358
2359             if (searchFlags & 4) {
2360                 ohbytes += 4;   /* if resume key required */
2361                         }   
2362
2363             if (infoLevel != 1
2364                  && infoLevel != 0x101
2365                  && infoLevel != 0x103)
2366                                 ohbytes += 4;   /* EASIZE */
2367
2368                         /* add header to name & term. null */
2369                         orbytes = onbytes + ohbytes + 1;
2370
2371                         /* now, we round up the record to a 4 byte alignment,
2372                          * and we make sure that we have enough room here for
2373                          * even the aligned version (so we don't have to worry
2374                          * about an * overflow when we pad things out below).
2375                          * That's the reason for the alignment arithmetic below.
2376              */
2377                         if (infoLevel >= 0x101)
2378                                 align = (4 - (orbytes & 3)) & 3;
2379                         else
2380                                 align = 0;
2381                         if (orbytes + bytesInBuffer + align > maxReturnData)
2382                 break;
2383
2384                         /* this is one of the entries to use: it is not deleted
2385                          * and it matches the star pattern we're looking for.
2386                          * Put out the name, preceded by its length.
2387              */
2388                         /* First zero everything else */
2389                         memset(origOp, 0, ohbytes);
2390
2391                         if (infoLevel <= 0x101)
2392                 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2393                         else if (infoLevel == 0x103)
2394                                 *((u_long *)(op + 8)) = onbytes;
2395                         else
2396                                 *((u_long *)(op + 60)) = onbytes;
2397             strcpy(origOp+ohbytes, dep->name);
2398
2399                         /* Short name if requested and needed */
2400             if (infoLevel == 0x104) {
2401                                 if (NeedShortName) {
2402                                         strcpy(op + 70, shortName);
2403                                         *(op + 68) = shortNameEnd - shortName;
2404                                 }
2405                         }
2406
2407             /* now, adjust the # of entries copied */
2408             returnedNames++;
2409
2410                         /* NextEntryOffset and FileIndex */
2411                         if (infoLevel >= 101) {
2412                                 int entryOffset = orbytes + align;
2413                                 *((u_long *)op) = entryOffset;
2414                                 *((u_long *)(op+4)) = nextEntryCookie;
2415                         }
2416
2417             /* now we emit the attribute.  This is tricky, since
2418              * we need to really stat the file to find out what
2419                          * type of entry we've got.  Right now, we're copying
2420                          * out data from * a buffer, while holding the scp
2421                          * locked, so it isn't really convenient to stat
2422                          * something now.  We'll put in a place holder
2423              * now, and make a second pass before returning this
2424                          * to get the real attributes.  So, we just skip the
2425                          * data for now, and adjust it later.  We allocate a
2426                          * patch record to make it easy to find this point
2427                          * later.  The replay will happen at a time when it is
2428                          * safe to unlock the directory.
2429              */
2430                         if (infoLevel != 0x103) {
2431                                 curPatchp = malloc(sizeof(*curPatchp));
2432                 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2433                           &curPatchp->q);
2434                                 curPatchp->dptr = op;
2435                                 if (infoLevel >= 0x101)
2436                                         curPatchp->dptr += 8;
2437
2438                 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
2439                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
2440                 }
2441                 else
2442                     curPatchp->flags = 0;
2443
2444                                 curPatchp->fid.cell = scp->fid.cell;
2445                                 curPatchp->fid.volume = scp->fid.volume;
2446                                 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2447                                 curPatchp->fid.unique = ntohl(dep->fid.unique);
2448
2449                 /* temp */
2450                 curPatchp->dep = dep;
2451                         }   
2452
2453                         if (searchFlags & 4)
2454                                 /* put out resume key */
2455                                 *((u_long *)origOp) = nextEntryCookie;
2456
2457                         /* Adjust byte ptr and count */
2458                         origOp += orbytes;      /* skip entire record */
2459             bytesInBuffer += orbytes;
2460
2461                         /* and pad the record out */
2462             while (--align >= 0) {
2463                                 *origOp++ = 0;
2464                 bytesInBuffer++;
2465             }
2466
2467                 }       /* if we're including this name */
2468         else if(!NeedShortName &&
2469                  !starPattern &&
2470                  !foundInexact &&
2471                                                         dep->fid.vnode != 0 &&
2472                  smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
2473             /* We were looking for exact matches, but here's an inexact one*/
2474             foundInexact = 1;
2475         }
2476                 
2477       nextEntry:
2478         /* and adjust curOffset to be where the new cookie is */
2479                 thyper.HighPart = 0;
2480         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2481         curOffset = LargeIntegerAdd(thyper, curOffset);
2482     }           /* while copying data for dir listing */
2483
2484     /* If we didn't get a star pattern, we did an exact match during the first pass. 
2485      * If there were no exact matches found, we fail over to inexact matches by
2486      * marking the query as a star pattern (matches all case permutations), and
2487      * re-running the query. 
2488      */
2489     if (returnedNames == 0 && !starPattern && foundInexact) {
2490         osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
2491         starPattern = 1;
2492         goto startsearch;
2493     }
2494
2495         /* release the mutex */
2496         lock_ReleaseMutex(&scp->mx);
2497     if (bufferp) buf_Release(bufferp);
2498
2499         /* apply and free last set of patches; if not doing a star match, this
2500          * will be empty, but better safe (and freeing everything) than sorry.
2501      */
2502     smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2503                               &req);
2504         
2505     /* now put out the final parameters */
2506         if (returnedNames == 0) eos = 1;
2507     if (p->opcode == 1) {
2508                 /* find first */
2509         outp->parmsp[0] = (unsigned short) dsp->cookie;
2510         outp->parmsp[1] = returnedNames;
2511         outp->parmsp[2] = eos;
2512         outp->parmsp[3] = 0;            /* nothing wrong with EAS */
2513         outp->parmsp[4] = 0;    
2514         /* don't need last name to continue
2515          * search, cookie is enough.  Normally,
2516          * this is the offset of the file name
2517          * of the last entry returned.
2518          */
2519         outp->totalParms = 10;  /* in bytes */
2520     }
2521     else {
2522         /* find next */
2523         outp->parmsp[0] = returnedNames;
2524         outp->parmsp[1] = eos;
2525         outp->parmsp[2] = 0;    /* EAS error */
2526         outp->parmsp[3] = 0;    /* last name, as above */
2527         outp->totalParms = 8;   /* in bytes */
2528     }   
2529
2530         /* return # of bytes in the buffer */
2531     outp->totalData = bytesInBuffer;
2532
2533         osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
2534               returnedNames, code);
2535
2536         /* Return error code if unsuccessful on first request */
2537         if (code == 0 && p->opcode == 1 && returnedNames == 0)
2538                 code = CM_ERROR_NOSUCHFILE;
2539
2540         /* if we're supposed to close the search after this request, or if
2541      * we're supposed to close the search if we're done, and we're done,
2542      * or if something went wrong, close the search.
2543      */
2544     /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2545         if ((searchFlags & 1) || (returnedNames == 0) || 
2546          ((searchFlags & 2) && eos) || code != 0)
2547             smb_DeleteDirSearch(dsp);
2548         if (code)
2549         smb_SendTran2Error(vcp, p, opx, code);
2550         else {
2551         smb_SendTran2Packet(vcp, outp, opx);
2552         }
2553         smb_FreeTran2Packet(outp);
2554     smb_ReleaseDirSearch(dsp);
2555     cm_ReleaseSCache(scp);
2556     cm_ReleaseUser(userp);
2557     return 0;
2558 }
2559
2560 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2561 {
2562     int dirHandle;
2563     smb_dirSearch_t *dsp;
2564
2565     dirHandle = smb_GetSMBParm(inp, 0);
2566         
2567     osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
2568
2569     dsp = smb_FindDirSearch(dirHandle);
2570         
2571     if (!dsp)
2572                 return CM_ERROR_BADFD;
2573         
2574     /* otherwise, we have an FD to destroy */
2575     smb_DeleteDirSearch(dsp);
2576     smb_ReleaseDirSearch(dsp);
2577         
2578         /* and return results */
2579         smb_SetSMBDataLength(outp, 0);
2580
2581     return 0;
2582 }
2583
2584 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2585 {
2586         smb_SetSMBDataLength(outp, 0);
2587     return 0;
2588 }
2589
2590 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2591 {
2592         char *pathp;
2593     long code = 0;
2594         cm_space_t *spacep;
2595     int excl;
2596     cm_user_t *userp;
2597     cm_scache_t *dscp;          /* dir we're dealing with */
2598     cm_scache_t *scp;           /* file we're creating */
2599     cm_attr_t setAttr;
2600     int initialModeBits;
2601     smb_fid_t *fidp;
2602     int attributes;
2603     char *lastNamep;
2604     long dosTime;
2605     int openFun;
2606     int trunc;
2607     int openMode;
2608     int extraInfo;
2609     int openAction;
2610     int parmSlot;                       /* which parm we're dealing with */
2611         char *tidPathp;
2612         cm_req_t req;
2613
2614         cm_InitReq(&req);
2615
2616     scp = NULL;
2617         
2618         extraInfo = (smb_GetSMBParm(inp, 2) & 1);       /* return extra info */
2619         openFun = smb_GetSMBParm(inp, 8);       /* open function */
2620     excl = ((openFun & 3) == 0);
2621     trunc = ((openFun & 3) == 2);               /* truncate it */
2622         openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2623     openAction = 0;                     /* tracks what we did */
2624
2625     attributes = smb_GetSMBParm(inp, 5);
2626     dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2627
2628         /* compute initial mode bits based on read-only flag in attributes */
2629     initialModeBits = 0666;
2630     if (attributes & 1) initialModeBits &= ~0222;
2631         
2632     pathp = smb_GetSMBData(inp, NULL);
2633
2634         spacep = inp->spacep;
2635     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2636
2637         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2638                 /* special case magic file name for receiving IOCTL requests
2639          * (since IOCTL calls themselves aren't getting through).
2640          */
2641 #ifdef NOTSERVICE
2642         osi_Log0(smb_logp, "IOCTL Open");
2643 #endif
2644
2645         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2646         smb_SetupIoctlFid(fidp, spacep);
2647
2648                 /* set inp->fid so that later read calls in same msg can find fid */
2649         inp->fid = fidp->fid;
2650         
2651         /* copy out remainder of the parms */
2652                 parmSlot = 2;
2653                 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2654                 if (extraInfo) {
2655             smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2656             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* mod time */
2657             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2658             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* len */
2659             smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2660             smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2661             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2662             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2663                 }   
2664                 /* and the final "always present" stuff */
2665         smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2666                 /* next write out the "unique" ID */
2667                 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2668                 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2669         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2670         smb_SetSMBDataLength(outp, 0);
2671
2672                 /* and clean up fid reference */
2673         smb_ReleaseFID(fidp);
2674         return 0;
2675     }
2676
2677 #ifdef DEBUG_VERBOSE
2678     {
2679         char *hexp, *asciip;
2680         asciip = (lastNamep ? lastNamep : pathp );
2681         hexp = osi_HexifyString(asciip);
2682         DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
2683         free(hexp);
2684     }
2685 #endif
2686     userp = smb_GetUser(vcp, inp);
2687
2688         dscp = NULL;
2689         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2690         code = cm_NameI(cm_rootSCachep, pathp,
2691                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2692                     userp, tidPathp, &req, &scp);
2693         if (code != 0) {
2694                 code = cm_NameI(cm_rootSCachep, spacep->data,
2695                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2696                         userp, tidPathp, &req, &dscp);
2697
2698         if (code) {
2699             cm_ReleaseUser(userp);
2700             return code;
2701         }
2702         
2703         /* otherwise, scp points to the parent directory.  Do a lookup,
2704          * and truncate the file if we find it, otherwise we create the
2705          * file.
2706          */
2707         if (!lastNamep) lastNamep = pathp;
2708         else lastNamep++;
2709         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2710                           &req, &scp);
2711         if (code && code != CM_ERROR_NOSUCHFILE) {
2712                         cm_ReleaseSCache(dscp);
2713             cm_ReleaseUser(userp);
2714             return code;
2715         }
2716         }
2717         
2718     /* if we get here, if code is 0, the file exists and is represented by
2719      * scp.  Otherwise, we have to create it.  The dir may be represented
2720      * by dscp, or we may have found the file directly.  If code is non-zero,
2721      * scp is NULL.
2722      */
2723         if (code == 0) {
2724         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2725         if (code) {
2726             if (dscp) cm_ReleaseSCache(dscp);
2727             cm_ReleaseSCache(scp);
2728             cm_ReleaseUser(userp);
2729             return code;
2730         }
2731
2732                 if (excl) {
2733                         /* oops, file shouldn't be there */
2734             if (dscp) cm_ReleaseSCache(dscp);
2735             cm_ReleaseSCache(scp);
2736             cm_ReleaseUser(userp);
2737             return CM_ERROR_EXISTS;
2738         }
2739
2740                 if (trunc) {
2741                         setAttr.mask = CM_ATTRMASK_LENGTH;
2742             setAttr.length.LowPart = 0;
2743             setAttr.length.HighPart = 0;
2744                         code = cm_SetAttr(scp, &setAttr, userp, &req);
2745             openAction = 3;     /* truncated existing file */
2746                 }
2747         else openAction = 1;    /* found existing file */
2748     }
2749         else if (!(openFun & 0x10)) {
2750                 /* don't create if not found */
2751         if (dscp) cm_ReleaseSCache(dscp);
2752         cm_ReleaseUser(userp);
2753         return CM_ERROR_NOSUCHFILE;
2754     }
2755     else {
2756                 osi_assert(dscp != NULL);
2757                 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
2758                  osi_LogSaveString(smb_logp, lastNamep));
2759                 openAction = 2; /* created file */
2760                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2761                 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2762         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2763                          &req);
2764                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2765                         smb_NotifyChange(FILE_ACTION_ADDED,
2766                              FILE_NOTIFY_CHANGE_FILE_NAME,
2767                              dscp, lastNamep, NULL, TRUE);
2768         if (!excl && code == CM_ERROR_EXISTS) {
2769                         /* not an exclusive create, and someone else tried
2770                          * creating it already, then we open it anyway.  We
2771                          * don't bother retrying after this, since if this next
2772                          * fails, that means that the file was deleted after we
2773                          * started this call.
2774              */
2775             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2776                              userp, &req, &scp);
2777             if (code == 0) {
2778                 if (trunc) {
2779                                         setAttr.mask = CM_ATTRMASK_LENGTH;
2780                     setAttr.length.LowPart = 0;
2781                     setAttr.length.HighPart = 0;
2782                     code = cm_SetAttr(scp, &setAttr, userp, &req);
2783                 }   
2784                         }       /* lookup succeeded */
2785         }
2786     }
2787         
2788         /* we don't need this any longer */
2789         if (dscp) cm_ReleaseSCache(dscp);
2790
2791     if (code) {
2792                 /* something went wrong creating or truncating the file */
2793         if (scp) cm_ReleaseSCache(scp);
2794         cm_ReleaseUser(userp);
2795         return code;
2796     }
2797         
2798         /* make sure we're about to open a file */
2799         if (scp->fileType != CM_SCACHETYPE_FILE) {
2800                 cm_ReleaseSCache(scp);
2801                 cm_ReleaseUser(userp);
2802                 return CM_ERROR_ISDIR;
2803         }
2804
2805     /* now all we have to do is open the file itself */
2806     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2807     osi_assert(fidp);
2808         
2809         /* save a pointer to the vnode */
2810     fidp->scp = scp;
2811         
2812         /* compute open mode */
2813     if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2814     if (openMode == 1 || openMode == 2)
2815         fidp->flags |= SMB_FID_OPENWRITE;
2816
2817         smb_ReleaseFID(fidp);
2818         
2819         cm_Open(scp, 0, userp);
2820
2821         /* set inp->fid so that later read calls in same msg can find fid */
2822     inp->fid = fidp->fid;
2823         
2824     /* copy out remainder of the parms */
2825         parmSlot = 2;
2826         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2827         lock_ObtainMutex(&scp->mx);
2828         if (extraInfo) {
2829         smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2830                 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2831         smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2832         smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2833         smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2834         smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2835         smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2836         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2837         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2838         }
2839         /* and the final "always present" stuff */
2840     smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2841         /* next write out the "unique" ID */
2842         smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2843         smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2844     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2845         lock_ReleaseMutex(&scp->mx);
2846     smb_SetSMBDataLength(outp, 0);
2847
2848         osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
2849
2850     cm_ReleaseUser(userp);
2851     /* leave scp held since we put it in fidp->scp */
2852     return 0;
2853 }   
2854
2855 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2856 {
2857         cm_req_t req;
2858         cm_user_t *userp;
2859         unsigned short fid;
2860         smb_fid_t *fidp;
2861         cm_scache_t *scp;
2862         unsigned char LockType;
2863         unsigned short NumberOfUnlocks, NumberOfLocks;
2864         unsigned long Timeout;
2865         char *op;
2866         LARGE_INTEGER LOffset, LLength;
2867         smb_waitingLock_t *waitingLock;
2868         void *lockp;
2869         long code = 0;
2870         int i;
2871
2872         cm_InitReq(&req);
2873
2874         fid = smb_GetSMBParm(inp, 2);
2875         fid = smb_ChainFID(fid, inp);
2876
2877         fidp = smb_FindFID(vcp, fid, 0);
2878         if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2879                 return CM_ERROR_BADFD;
2880         }
2881         /* set inp->fid so that later read calls in same msg can find fid */
2882     inp->fid = fid;
2883
2884         userp = smb_GetUser(vcp, inp);
2885
2886         scp = fidp->scp;
2887
2888         lock_ObtainMutex(&scp->mx);
2889         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2890                          CM_SCACHESYNC_NEEDCALLBACK
2891                          | CM_SCACHESYNC_GETSTATUS
2892                          | CM_SCACHESYNC_LOCK);
2893         if (code) goto doneSync;
2894
2895         LockType = smb_GetSMBParm(inp, 3) & 0xff;
2896         Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2897         NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2898         NumberOfLocks = smb_GetSMBParm(inp, 7);
2899
2900         op = smb_GetSMBData(inp, NULL);
2901
2902         for (i=0; i<NumberOfUnlocks; i++) {
2903                 if (LockType & 0x10) {
2904                         /* Large Files */
2905                         LOffset.HighPart = *((LONG *)(op + 4));
2906                         LOffset.LowPart = *((DWORD *)(op + 8));
2907                         LLength.HighPart = *((LONG *)(op + 12));
2908                         LLength.LowPart = *((DWORD *)(op + 16));
2909                         op += 20;
2910                 }
2911                 else {
2912                         /* Not Large Files */
2913                         LOffset.HighPart = 0;
2914                         LOffset.LowPart = *((DWORD *)(op + 2));
2915                         LLength.HighPart = 0;
2916                         LLength.LowPart = *((DWORD *)(op + 6));
2917                         op += 10;
2918                 }
2919                 if (LargeIntegerNotEqualToZero(LOffset))
2920                         continue;
2921                 /* Do not check length -- length check done in cm_Unlock */
2922
2923                 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2924                 if (code) goto done;
2925         }
2926
2927         for (i=0; i<NumberOfLocks; i++) {
2928                 if (LockType & 0x10) {
2929                         /* Large Files */
2930                         LOffset.HighPart = *((LONG *)(op + 4));
2931                         LOffset.LowPart = *((DWORD *)(op + 8));
2932                         LLength.HighPart = *((LONG *)(op + 12));
2933                         LLength.LowPart = *((DWORD *)(op + 16));
2934                         op += 20;
2935                 }
2936                 else {
2937                         /* Not Large Files */
2938                         LOffset.HighPart = 0;
2939                         LOffset.LowPart = *((DWORD *)(op + 2));
2940                         LLength.HighPart = 0;
2941                         LLength.LowPart = *((DWORD *)(op + 6));
2942                         op += 10;
2943                 }
2944                 if (LargeIntegerNotEqualToZero(LOffset))
2945                         continue;
2946                 if (LargeIntegerLessThan(LOffset, scp->length))
2947                         continue;
2948
2949                 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2950                                 userp, &req, &lockp);
2951                 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2952                         /* Put on waiting list */
2953                         waitingLock = malloc(sizeof(smb_waitingLock_t));
2954                         waitingLock->vcp = vcp;
2955                         waitingLock->inp = smb_CopyPacket(inp);
2956                         waitingLock->outp = smb_CopyPacket(outp);
2957                         waitingLock->timeRemaining = Timeout;
2958                         waitingLock->lockp = lockp;
2959                         lock_ObtainWrite(&smb_globalLock);
2960                         osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2961                                  &waitingLock->q);
2962                         osi_Wakeup((long) &smb_allWaitingLocks);
2963                         lock_ReleaseWrite(&smb_globalLock);
2964                         /* don't send reply immediately */
2965                         outp->flags |= SMB_PACKETFLAG_NOSEND;
2966                 }
2967                 if (code) break;
2968         }
2969
2970         if (code) {
2971                 /* release any locks acquired before the failure */
2972         }
2973         else
2974                 smb_SetSMBDataLength(outp, 0);
2975 done:
2976         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2977 doneSync:
2978         lock_ReleaseMutex(&scp->mx);
2979         cm_ReleaseUser(userp);
2980         smb_ReleaseFID(fidp);
2981
2982         return code;
2983 }
2984
2985 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2986 {
2987         unsigned short fid;
2988     smb_fid_t *fidp;
2989     cm_scache_t *scp;
2990     long code = 0;
2991     long searchTime;
2992     cm_user_t *userp;
2993         cm_req_t req;
2994
2995         cm_InitReq(&req);
2996
2997     fid = smb_GetSMBParm(inp, 0);
2998     fid = smb_ChainFID(fid, inp);
2999         
3000     fidp = smb_FindFID(vcp, fid, 0);
3001     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
3002                 return CM_ERROR_BADFD;
3003     }
3004         
3005     userp = smb_GetUser(vcp, inp);
3006         
3007     scp = fidp->scp;
3008         
3009     /* otherwise, stat the file */
3010         lock_ObtainMutex(&scp->mx);
3011     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3012                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3013         if (code) goto done;
3014
3015         /* decode times.  We need a search time, but the response to this
3016      * call provides the date first, not the time, as returned in the
3017      * searchTime variable.  So we take the high-order bits first.
3018      */
3019         smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
3020     smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff);       /* ctime */
3021     smb_SetSMBParm(outp, 1, searchTime & 0xffff);
3022     smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff);       /* atime */
3023     smb_SetSMBParm(outp, 3, searchTime & 0xffff);
3024     smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff);       /* mtime */
3025     smb_SetSMBParm(outp, 5, searchTime & 0xffff);
3026
3027     /* now handle file size and allocation size */
3028     smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff);              /* file size */
3029     smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
3030     smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff);              /* alloc size */
3031     smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
3032
3033         /* file attribute */
3034     smb_SetSMBParm(outp, 10, smb_Attributes(scp));
3035         
3036     /* and finalize stuff */
3037     smb_SetSMBDataLength(outp, 0);
3038     code = 0;
3039
3040   done:
3041         lock_ReleaseMutex(&scp->mx);
3042         cm_ReleaseUser(userp);
3043         smb_ReleaseFID(fidp);
3044         return code;
3045 }
3046
3047 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3048 {
3049         unsigned short fid;
3050     smb_fid_t *fidp;
3051     cm_scache_t *scp;
3052     long code = 0;
3053         long searchTime;
3054     long unixTime;
3055     cm_user_t *userp;
3056     cm_attr_t attrs;
3057         cm_req_t req;
3058
3059         cm_InitReq(&req);
3060
3061     fid = smb_GetSMBParm(inp, 0);
3062     fid = smb_ChainFID(fid, inp);
3063         
3064     fidp = smb_FindFID(vcp, fid, 0);
3065     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
3066                 return CM_ERROR_BADFD;
3067     }
3068         
3069     userp = smb_GetUser(vcp, inp);
3070         
3071     scp = fidp->scp;
3072         
3073         /* now prepare to call cm_setattr.  This message only sets various times,
3074      * and AFS only implements mtime, and we'll set the mtime if that's
3075      * requested.  The others we'll ignore.
3076      */
3077         searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
3078         
3079     if (searchTime != 0) {
3080                 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
3081
3082         if ( unixTime != -1 ) {
3083             attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
3084             attrs.clientModTime = unixTime;
3085             code = cm_SetAttr(scp, &attrs, userp, &req);
3086
3087             osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
3088         } else {
3089             osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
3090         }
3091     }
3092     else code = 0;
3093
3094         cm_ReleaseUser(userp);
3095         smb_ReleaseFID(fidp);
3096         return code;
3097 }
3098
3099
3100 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3101 {
3102         osi_hyper_t offset;
3103     long count, finalCount;
3104     unsigned short fd;
3105     smb_fid_t *fidp;
3106     long code = 0;
3107     cm_user_t *userp;
3108     char *op;
3109         
3110     fd = smb_GetSMBParm(inp, 2);
3111     count = smb_GetSMBParm(inp, 5);
3112     offset.HighPart = 0;        /* too bad */
3113     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
3114
3115     osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
3116              fd, offset.LowPart, count);
3117         
3118         fd = smb_ChainFID(fd, inp);
3119     fidp = smb_FindFID(vcp, fd, 0);
3120     if (!fidp) {
3121                 return CM_ERROR_BADFD;
3122     }
3123         /* set inp->fid so that later read calls in same msg can find fid */
3124     inp->fid = fd;
3125
3126     if (fidp->flags & SMB_FID_IOCTL) {
3127                 return smb_IoctlV3Read(fidp, vcp, inp, outp);
3128     }
3129         
3130         userp = smb_GetUser(vcp, inp);
3131
3132         /* 0 and 1 are reserved for request chaining, were setup by our caller,
3133      * and will be further filled in after we return.
3134      */
3135     smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
3136     smb_SetSMBParm(outp, 3, 0); /* resvd */
3137     smb_SetSMBParm(outp, 4, 0); /* resvd */
3138         smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
3139     /* fill in #6 when we have all the parameters' space reserved */
3140     smb_SetSMBParm(outp, 7, 0); /* resv'd */
3141     smb_SetSMBParm(outp, 8, 0); /* resv'd */
3142     smb_SetSMBParm(outp, 9, 0); /* resv'd */
3143     smb_SetSMBParm(outp, 10, 0);        /* resv'd */
3144         smb_SetSMBParm(outp, 11, 0);    /* reserved */
3145
3146         /* get op ptr after putting in the parms, since otherwise we don't
3147      * know where the data really is.
3148      */
3149     op = smb_GetSMBData(outp, NULL);
3150         
3151     /* now fill in offset from start of SMB header to first data byte (to op) */
3152     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
3153
3154         /* set the packet data length the count of the # of bytes */
3155     smb_SetSMBDataLength(outp, count);
3156
3157 #ifndef DJGPP
3158         code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
3159 #else /* DJGPP */
3160         code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
3161 #endif /* !DJGPP */
3162
3163         /* fix some things up */
3164         smb_SetSMBParm(outp, 5, finalCount);
3165         smb_SetSMBDataLength(outp, finalCount);
3166
3167     smb_ReleaseFID(fidp);
3168
3169     cm_ReleaseUser(userp);
3170     return code;
3171 }   
3172         
3173 /*
3174  * Values for createDisp, copied from NTDDK.H
3175  *
3176  *  FILE_SUPERSEDE      0       (???)
3177  *  FILE_OPEN           1       (open)
3178  *  FILE_CREATE         2       (exclusive)
3179  *  FILE_OPEN_IF        3       (non-exclusive)
3180  *  FILE_OVERWRITE      4       (open & truncate, but do not create)
3181  *  FILE_OVERWRITE_IF   5       (open & truncate, or create)
3182  */
3183
3184 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3185 {
3186         char *pathp, *realPathp;
3187         long code = 0;
3188         cm_space_t *spacep;
3189         cm_user_t *userp;
3190         cm_scache_t *dscp;              /* parent dir */
3191         cm_scache_t *scp;               /* file to create or open */
3192         cm_attr_t setAttr;
3193         char *lastNamep;
3194     char *treeStartp;
3195         unsigned short nameLength;
3196         unsigned int flags;
3197         unsigned int requestOpLock;
3198         unsigned int requestBatchOpLock;
3199         unsigned int mustBeDir;
3200     unsigned int treeCreate;
3201         int realDirFlag;
3202         unsigned int desiredAccess;
3203         unsigned int extAttributes;
3204         unsigned int createDisp;
3205         unsigned int createOptions;
3206         int initialModeBits;
3207         unsigned short baseFid;
3208         smb_fid_t *baseFidp;
3209         smb_fid_t *fidp;
3210         cm_scache_t *baseDirp;
3211         unsigned short openAction;
3212         int parmSlot;
3213         long fidflags;
3214         FILETIME ft;
3215         LARGE_INTEGER sz;
3216         char *tidPathp;
3217         BOOL foundscp;
3218         cm_req_t req;
3219
3220         cm_InitReq(&req);
3221
3222     treeCreate = FALSE;
3223         foundscp = FALSE;
3224         scp = NULL;
3225
3226         nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3227         flags = smb_GetSMBOffsetParm(inp, 3, 1)
3228                   | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3229         requestOpLock = flags & 0x02;
3230         requestBatchOpLock = flags & 0x04;
3231         mustBeDir = flags & 0x08;
3232
3233         /*
3234          * Why all of a sudden 32-bit FID?
3235          * We will reject all bits higher than 16.
3236          */
3237         if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3238                 return CM_ERROR_INVAL;
3239         baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3240         desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3241                           | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3242         extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3243                           | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3244         createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3245                         | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3246         createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3247                           | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3248
3249         /* mustBeDir is never set; createOptions directory bit seems to be
3250      * more important
3251          */
3252         if (createOptions & 1)
3253                 realDirFlag = 1;
3254         else if (createOptions & 0x40)
3255                 realDirFlag = 0;
3256         else
3257                 realDirFlag = -1;
3258
3259         /*
3260          * compute initial mode bits based on read-only flag in
3261          * extended attributes
3262          */
3263         initialModeBits = 0666;
3264         if (extAttributes & 1) initialModeBits &= ~0222;
3265
3266         pathp = smb_GetSMBData(inp, NULL);
3267         /* Sometimes path is not null-terminated, so we make a copy. */
3268         realPathp = malloc(nameLength+1);
3269         memcpy(realPathp, pathp, nameLength);
3270         realPathp[nameLength] = 0;
3271
3272         spacep = inp->spacep;
3273         smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3274
3275     osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
3276     osi_Log4(smb_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
3277
3278         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3279                 /* special case magic file name for receiving IOCTL requests
3280                  * (since IOCTL calls themselves aren't getting through).
3281                  */
3282                 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3283                 smb_SetupIoctlFid(fidp, spacep);
3284
3285                 /* set inp->fid so that later read calls in same msg can find fid */
3286                 inp->fid = fidp->fid;
3287
3288                 /* out parms */
3289                 parmSlot = 2;
3290                 smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
3291                 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3292                 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3293                 /* times */
3294                 memset(&ft, 0, sizeof(ft));
3295                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3296                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3297                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3298                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3299                 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3300                 sz.HighPart = 0x7fff; sz.LowPart = 0;
3301                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3302                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3303                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
3304                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
3305                 smb_SetSMBParmByte(outp, parmSlot, 0);  /* is a dir? */
3306                 smb_SetSMBDataLength(outp, 0);
3307
3308                 /* clean up fid reference */
3309                 smb_ReleaseFID(fidp);
3310                 free(realPathp);
3311                 return 0;
3312         }
3313
3314 #ifdef DEBUG_VERBOSE
3315     {
3316         char *hexp, *asciip;
3317         asciip = (lastNamep? lastNamep : realPathp);
3318         hexp = osi_HexifyString( asciip );
3319         DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
3320         free(hexp);
3321     }
3322 #endif
3323     userp = smb_GetUser(vcp, inp);
3324     if (!userp) {
3325         osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
3326         free(realPathp);
3327         return CM_ERROR_INVAL;
3328     }
3329
3330         if (baseFid == 0) {
3331                 baseDirp = cm_rootSCachep;
3332                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3333         }
3334         else {
3335         baseFidp = smb_FindFID(vcp, baseFid, 0);
3336         if (!baseFidp) {
3337                 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
3338                 free(realPathp);
3339                 cm_ReleaseUser(userp);
3340                 return CM_ERROR_INVAL;
3341         }
3342                 baseDirp = baseFidp->scp;
3343                 tidPathp = NULL;
3344         }
3345
3346     osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
3347         
3348     /* compute open mode */
3349         fidflags = 0;
3350         if (desiredAccess & DELETE)
3351                 fidflags |= SMB_FID_OPENDELETE;
3352         if (desiredAccess & AFS_ACCESS_READ)
3353                 fidflags |= SMB_FID_OPENREAD;
3354         if (desiredAccess & AFS_ACCESS_WRITE)
3355                 fidflags |= SMB_FID_OPENWRITE;
3356
3357         dscp = NULL;
3358         code = 0;
3359     /* For an exclusive create, we want to do a case sensitive match for the last component. */
3360     if (createDisp == 2 || createDisp == 4 || createDisp == 5) {
3361         code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3362                         userp, tidPathp, &req, &dscp);
3363         if (code == 0) {
3364             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
3365                              userp, &req, &scp);
3366             if (code == CM_ERROR_NOSUCHFILE) {
3367                 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
3368                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
3369                 if (code == 0 && realDirFlag == 1) {
3370                                         cm_ReleaseSCache(scp);
3371                     cm_ReleaseSCache(dscp);
3372                     cm_ReleaseUser(userp);
3373                     free(realPathp);
3374                     return CM_ERROR_EXISTS;
3375                 }
3376             }
3377         } else
3378             dscp = NULL;
3379     } else {
3380         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3381                         userp, tidPathp, &req, &scp);
3382     }
3383     if (code == 0) 
3384                 foundscp = TRUE;
3385
3386         if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3387                 /* look up parent directory */
3388         /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
3389          * the immediate parent.  We have to work our way up realPathp until we hit something that we
3390          * recognize.
3391          */
3392
3393         if ( !dscp ) {
3394             while (1) {
3395                 char *tp;
3396
3397                 code = cm_NameI(baseDirp, spacep->data,
3398                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3399                              userp, tidPathp, &req, &dscp);
3400
3401                 if (code && 
3402                      (tp = strrchr(spacep->data,'\\')) &&
3403                      (createDisp == 2) &&
3404                      (realDirFlag == 1)) {
3405                     *tp++ = 0;
3406                     treeCreate = TRUE;
3407                     treeStartp = realPathp + (tp - spacep->data);
3408
3409                     if (*tp && !smb_IsLegalFilename(tp)) {
3410                         if(baseFid != 0) 
3411                             smb_ReleaseFID(baseFidp);
3412                         cm_ReleaseUser(userp);
3413                         free(realPathp);
3414                         return CM_ERROR_BADNTFILENAME;
3415                     }
3416                 }
3417                 else
3418                     break;
3419             }
3420         } else
3421             code = 0;
3422
3423         if (baseFid != 0) 
3424                         smb_ReleaseFID(baseFidp);
3425
3426         if (code) {
3427             osi_Log0(smb_logp,"NTCreateX parent not found");
3428             cm_ReleaseUser(userp);
3429             free(realPathp);
3430             return code;
3431         }
3432
3433         if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
3434             /* A file exists where we want a directory. */
3435             cm_ReleaseSCache(dscp);
3436             cm_ReleaseUser(userp);
3437             free(realPathp);
3438             return CM_ERROR_EXISTS;
3439         }
3440
3441         if (!lastNamep) 
3442             lastNamep = realPathp;
3443         else 
3444             lastNamep++;
3445
3446         if (!smb_IsLegalFilename(lastNamep)) {
3447             cm_ReleaseSCache(dscp);
3448             cm_ReleaseUser(userp);
3449             free(realPathp);
3450             return CM_ERROR_BADNTFILENAME;
3451         }
3452
3453         if (!foundscp && !treeCreate) {
3454             if(createDisp == 2 || createDisp == 4)
3455                 code = cm_Lookup(dscp, lastNamep,
3456                                   CM_FLAG_FOLLOW, userp, &req, &scp);
3457             else
3458                 code = cm_Lookup(dscp, lastNamep,
3459                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3460                                  userp, &req, &scp);
3461                         if (code && code != CM_ERROR_NOSUCHFILE) {
3462                                 cm_ReleaseSCache(dscp);
3463                                 cm_ReleaseUser(userp);
3464                                 free(realPathp);
3465                                 return code;
3466                         }
3467                 }
3468         }
3469         else {
3470                 if (baseFid != 0) 
3471                         smb_ReleaseFID(baseFidp);
3472         }
3473
3474         /* if we get here, if code is 0, the file exists and is represented by
3475          * scp.  Otherwise, we have to create it.  The dir may be represented
3476          * by dscp, or we may have found the file directly.  If code is non-zero,
3477          * scp is NULL.
3478          */
3479         if (code == 0 && !treeCreate) {
3480                 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3481                                       &req);
3482                 if (code) {
3483                         if (dscp) cm_ReleaseSCache(dscp);
3484                         cm_ReleaseSCache(scp);
3485                         cm_ReleaseUser(userp);
3486                         free(realPathp);
3487                         return code;
3488                 }
3489
3490                 if (createDisp == 2) {
3491                         /* oops, file shouldn't be there */
3492                         if (dscp) cm_ReleaseSCache(dscp);
3493                         cm_ReleaseSCache(scp);
3494                         cm_ReleaseUser(userp);
3495                         free(realPathp);
3496                         return CM_ERROR_EXISTS;
3497                 }
3498
3499                 if (createDisp == 4
3500                     || createDisp == 5) {
3501                         setAttr.mask = CM_ATTRMASK_LENGTH;
3502                         setAttr.length.LowPart = 0;
3503                         setAttr.length.HighPart = 0;
3504                         code = cm_SetAttr(scp, &setAttr, userp, &req);
3505                         openAction = 3; /* truncated existing file */
3506                 }
3507                 else openAction = 1;    /* found existing file */
3508         }
3509         else if (createDisp == 1 || createDisp == 4) {
3510                 /* don't create if not found */
3511                 if (dscp) cm_ReleaseSCache(dscp);
3512                 cm_ReleaseUser(userp);
3513                 free(realPathp);
3514                 return CM_ERROR_NOSUCHFILE;
3515         }
3516         else if (realDirFlag == 0 || realDirFlag == -1) {
3517                 osi_assert(dscp != NULL);
3518                 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
3519                                 osi_LogSaveString(smb_logp, lastNamep));
3520                 openAction = 2;         /* created file */
3521                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3522                 setAttr.clientModTime = time(NULL);
3523                 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3524                                  &req);
3525                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3526                         smb_NotifyChange(FILE_ACTION_ADDED,
3527                                          FILE_NOTIFY_CHANGE_FILE_NAME,
3528                                          dscp, lastNamep, NULL, TRUE);
3529                 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3530                         /* Not an exclusive create, and someone else tried
3531                          * creating it already, then we open it anyway.  We
3532                          * don't bother retrying after this, since if this next
3533                          * fails, that means that the file was deleted after we
3534                          * started this call.
3535                          */
3536                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3537                                          userp, &req, &scp);
3538                         if (code == 0) {
3539                                 if (createDisp == 5) {
3540                                         setAttr.mask = CM_ATTRMASK_LENGTH;
3541                                         setAttr.length.LowPart = 0;
3542                                         setAttr.length.HighPart = 0;
3543                                         code = cm_SetAttr(scp, &setAttr, userp,
3544                                                           &req);
3545                                 }
3546                         }       /* lookup succeeded */
3547                 }
3548         }
3549         else {
3550         char *tp, *pp;
3551         char *cp; /* This component */
3552         int clen = 0; /* length of component */
3553         cm_scache_t *tscp;
3554         int isLast = 0;
3555                 
3556         /* create directory */
3557                 if ( !treeCreate ) treeStartp = lastNamep;
3558         osi_assert(dscp != NULL);
3559         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
3560                                 osi_LogSaveString(smb_logp, treeStartp));
3561                 openAction = 2;         /* created directory */
3562
3563                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3564                 setAttr.clientModTime = time(NULL);
3565                 
3566                 pp = treeStartp;
3567                 cp = spacep->data;
3568                 tscp = dscp;
3569
3570                 while(pp && *pp) {
3571                         tp = strchr(pp, '\\');
3572                         if(!tp) {
3573                                 strcpy(cp,pp);
3574                 clen = strlen(cp);
3575                                 isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
3576                         }
3577                         else {
3578                                 clen = tp - pp;
3579                                 strncpy(cp,pp,clen);
3580                                 *(cp + clen) = 0;
3581                                 tp++;
3582                         }
3583                         pp = tp;
3584
3585                         if(clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
3586
3587                         /* cp is the next component to be created. */
3588                         code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
3589                         if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
3590                                 smb_NotifyChange(FILE_ACTION_ADDED,
3591                                 FILE_NOTIFY_CHANGE_DIR_NAME,
3592                                 tscp, cp, NULL, TRUE);
3593                         if (code == 0 || 
3594                                 (code == CM_ERROR_EXISTS && createDisp != 2)) {
3595                                         /* Not an exclusive create, and someone else tried
3596                                         * creating it already, then we open it anyway.  We
3597                                         * don't bother retrying after this, since if this next
3598                                         * fails, that means that the file was deleted after we
3599                                         * started this call.
3600                                         */
3601                                         code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
3602                                                 userp, &req, &scp);
3603                                 }
3604                         if(code) break;
3605
3606                         if(!isLast) { /* for anything other than dscp, release it unless it's the last one */
3607                                 cm_ReleaseSCache(tscp);
3608                                 tscp = scp; /* Newly created directory will be next parent */
3609                         }
3610                 }
3611
3612                 /* 
3613                 if we get here and code == 0, then scp is the last directory created, and tscp is the
3614                 parent of scp.  dscp got released if dscp != tscp. both tscp and scp are held.
3615                 */
3616                 dscp = tscp;
3617         }
3618
3619         if (code) {
3620                 /* something went wrong creating or truncating the file */
3621                 if (scp) cm_ReleaseSCache(scp);
3622         if (dscp) cm_ReleaseSCache(dscp);
3623                 cm_ReleaseUser(userp);
3624                 free(realPathp);
3625                 return code;
3626         }
3627
3628         /* make sure we have file vs. dir right (only applies for single component case) */
3629         if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3630                 cm_ReleaseSCache(scp);
3631         if (dscp) cm_ReleaseSCache(dscp);
3632                 cm_ReleaseUser(userp);
3633                 free(realPathp);
3634                 return CM_ERROR_ISDIR;
3635         }
3636     /* (only applies to single component case) */
3637         if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3638                 cm_ReleaseSCache(scp);
3639         if (dscp) cm_ReleaseSCache(dscp);
3640                 cm_ReleaseUser(userp);
3641                 free(realPathp);
3642                 return CM_ERROR_NOTDIR;
3643         }
3644
3645         /* open the file itself */
3646         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3647         osi_assert(fidp);
3648         /* save a pointer to the vnode */
3649         fidp->scp = scp;
3650
3651         fidp->flags = fidflags;
3652
3653         /* save parent dir and pathname for delete or change notification */
3654         if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3655                 fidp->flags |= SMB_FID_NTOPEN;
3656                 fidp->NTopen_dscp = dscp;
3657                 cm_HoldSCache(dscp);
3658                 fidp->NTopen_pathp = strdup(lastNamep);
3659         }
3660         fidp->NTopen_wholepathp = realPathp;
3661
3662         /* we don't need this any longer */
3663         if (dscp) cm_ReleaseSCache(dscp);
3664         cm_Open(scp, 0, userp);
3665
3666         /* set inp->fid so that later read calls in same msg can find fid */
3667         inp->fid = fidp->fid;
3668
3669         /* out parms */
3670         parmSlot = 2;
3671         lock_ObtainMutex(&scp->mx);
3672         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
3673         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3674         smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3675         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3676         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3677         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3678         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3679         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3680         smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3681                                                 parmSlot += 2;
3682         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3683         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3684         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
3685         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
3686         smb_SetSMBParmByte(outp, parmSlot,
3687                 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3688         lock_ReleaseMutex(&scp->mx);
3689         smb_SetSMBDataLength(outp, 0);
3690
3691         osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3692                  osi_LogSaveString(smb_logp, realPathp));
3693
3694         smb_ReleaseFID(fidp);
3695
3696         cm_ReleaseUser(userp);
3697
3698     /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
3699
3700         /* leave scp held since we put it in fidp->scp */
3701         return 0;
3702 }
3703
3704 /*
3705  * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3706  * Instead, ultimately, would like to use a subroutine for common code.
3707  */
3708 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3709 {
3710         char *pathp, *realPathp;
3711         long code = 0;
3712         cm_space_t *spacep;
3713         cm_user_t *userp;
3714         cm_scache_t *dscp;              /* parent dir */
3715         cm_scache_t *scp;               /* file to create or open */
3716         cm_attr_t setAttr;
3717         char *lastNamep;
3718         unsigned long nameLength;
3719         unsigned int flags;
3720         unsigned int requestOpLock;
3721         unsigned int requestBatchOpLock;
3722         unsigned int mustBeDir;
3723     unsigned int extendedRespRequired;
3724         int realDirFlag;
3725         unsigned int desiredAccess;
3726 #ifdef DEBUG_VERBOSE    
3727     unsigned int allocSize;
3728     unsigned int shareAccess;
3729 #endif
3730         unsigned int extAttributes;
3731         unsigned int createDisp;
3732 #ifdef DEBUG_VERBOSE
3733     unsigned int sdLen;
3734 #endif
3735         unsigned int createOptions;
3736         int initialModeBits;
3737         unsigned short baseFid;
3738         smb_fid_t *baseFidp;
3739         smb_fid_t *fidp;
3740         cm_scache_t *baseDirp;
3741         unsigned short openAction;
3742         int parmSlot;
3743         long fidflags;
3744         FILETIME ft;
3745         char *tidPathp;
3746         BOOL foundscp;
3747         int parmOffset, dataOffset;
3748         char *parmp;
3749         ULONG *lparmp;
3750         char *outData;
3751         cm_req_t req;
3752
3753         cm_InitReq(&req);
3754
3755         foundscp = FALSE;
3756         scp = NULL;
3757
3758         parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3759                         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3760         parmp = inp->data + parmOffset;
3761         lparmp = (ULONG *) parmp;
3762
3763         flags = lparmp[0];
3764         requestOpLock = flags & 0x02;
3765         requestBatchOpLock = flags & 0x04;
3766         mustBeDir = flags & 0x08;
3767     extendedRespRequired = flags & 0x10;
3768
3769         /*
3770          * Why all of a sudden 32-bit FID?
3771          * We will reject all bits higher than 16.
3772          */
3773         if (lparmp[1] & 0xFFFF0000)
3774                 return CM_ERROR_INVAL;
3775         baseFid = (unsigned short)lparmp[1];
3776         desiredAccess = lparmp[2];
3777 #ifdef DEBUG_VERBOSE
3778     allocSize = lparmp[3];
3779 #endif /* DEBUG_VERSOSE */
3780         extAttributes = lparmp[5];
3781 #ifdef DEBUG_VEROSE
3782     shareAccess = lparmp[6];
3783 #endif
3784         createDisp = lparmp[7];
3785         createOptions = lparmp[8];
3786 #ifdef DEBUG_VERBOSE
3787     sdLen = lparmp[9];
3788 #endif
3789         nameLength = lparmp[11];
3790
3791 #ifdef DEBUG_VERBOSE
3792         osi_Log4(smb_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
3793         osi_Log2(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
3794         osi_Log1(smb_logp,"... flags[%x]",flags);
3795 #endif
3796
3797         /* mustBeDir is never set; createOptions directory bit seems to be
3798          * more important
3799          */
3800         if (createOptions & 1)
3801                 realDirFlag = 1;
3802         else if (createOptions & 0x40)
3803                 realDirFlag = 0;
3804         else
3805                 realDirFlag = -1;
3806
3807         /*
3808          * compute initial mode bits based on read-only flag in
3809          * extended attributes
3810          */
3811         initialModeBits = 0666;
3812         if (extAttributes & 1) initialModeBits &= ~0222;
3813
3814         pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3815         /* Sometimes path is not null-terminated, so we make a copy. */
3816         realPathp = malloc(nameLength+1);
3817         memcpy(realPathp, pathp, nameLength);
3818         realPathp[nameLength] = 0;
3819
3820         spacep = cm_GetSpace();
3821         smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3822
3823         /*
3824          * Nothing here to handle SMB_IOCTL_FILENAME.
3825          * Will add it if necessary.
3826          */
3827
3828 #ifdef DEBUG_VERBOSE
3829         {
3830                 char *hexp, *asciip;
3831                 asciip = (lastNamep? lastNamep : realPathp);
3832                 hexp = osi_HexifyString( asciip );
3833                 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
3834                 free(hexp);
3835         }
3836 #endif
3837
3838         userp = smb_GetUser(vcp, inp);
3839     if(!userp) {
3840         osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
3841         free(realPathp);
3842         return CM_ERROR_INVAL;
3843     }
3844
3845         if (baseFid == 0) {
3846                 baseDirp = cm_rootSCachep;
3847                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3848         }
3849         else {
3850         baseFidp = smb_FindFID(vcp, baseFid, 0);
3851         if(!baseFidp) {
3852                 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
3853                 free(realPathp);
3854                 cm_ReleaseUser(userp);
3855                 return CM_ERROR_INVAL;
3856         }
3857                 baseDirp = baseFidp->scp;
3858                 tidPathp = NULL;
3859         }
3860
3861     /* compute open mode */
3862     fidflags = 0;
3863     if (desiredAccess & DELETE)
3864         fidflags |= SMB_FID_OPENDELETE;
3865     if (desiredAccess & AFS_ACCESS_READ)
3866         fidflags |= SMB_FID_OPENREAD;
3867     if (desiredAccess & AFS_ACCESS_WRITE)
3868         fidflags |= SMB_FID_OPENWRITE;
3869
3870         dscp = NULL;
3871         code = 0;
3872     if (createDisp == 2 || createDisp == 4 || createDisp == 5) {
3873         code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3874                         userp, tidPathp, &req, &dscp);
3875         if (code == 0) {
3876             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
3877                              userp, &req, &scp);
3878             if (code == CM_ERROR