afsd-20040506
[openafs.git] / src / WINNT / afsd / smb3.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #ifndef DJGPP
14 #include <windows.h>
15 #endif /* !DJGPP */
16 #include <stdlib.h>
17 #include <malloc.h>
18 #include <string.h>
19 #include <stdio.h>
20 #include <time.h>
21
22 #include <osi.h>
23
24 #include "afsd.h"
25
26 #include "smb.h"
27
28 extern osi_hyper_t hzero;
29
30 smb_packet_t *smb_Directory_Watches = NULL;
31 osi_mutex_t smb_Dir_Watch_Lock;
32
33 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
34
35 /* protected by the smb_globalLock */
36 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
37
38 /* retrieve a held reference to a user structure corresponding to an incoming
39  * request */
40 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
41 {
42         smb_user_t *uidp;
43     cm_user_t *up = NULL;
44         
45     uidp = smb_FindUID(vcp, inp->uid, 0);
46     if (!uidp) return NULL;
47         
48         lock_ObtainMutex(&uidp->mx);
49     if (uidp->unp) {
50         up = uidp->unp->userp;
51         cm_HoldUser(up);
52     }
53         lock_ReleaseMutex(&uidp->mx);
54
55     smb_ReleaseUID(uidp);
56
57     return up;
58 }
59
60 /*
61  * Return extended attributes.
62  * Right now, we aren't using any of the "new" bits, so this looks exactly
63  * like smb_Attributes() (see smb.c).
64  */
65 unsigned long smb_ExtAttributes(cm_scache_t *scp)
66 {
67         unsigned long attrs;
68
69         if (scp->fileType == CM_SCACHETYPE_DIRECTORY
70             || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
71                 attrs = SMB_ATTR_DIRECTORY;
72         else
73                 attrs = 0;
74         /*
75          * We used to mark a file RO if it was in an RO volume, but that
76          * turns out to be impolitic in NT.  See defect 10007.
77          */
78 #ifdef notdef
79         if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
80 #endif
81         if ((scp->unixModeBits & 0222) == 0)
82                 attrs |= SMB_ATTR_READONLY;             /* Read-only */
83
84         if (attrs == 0)
85                 attrs = SMB_ATTR_NORMAL;                /* FILE_ATTRIBUTE_NORMAL */
86
87         return attrs;
88 }
89
90 int smb_V3IsStarMask(char *maskp)
91 {
92     char tc;
93
94         while (tc = *maskp++)
95         if (tc == '?' || tc == '*') 
96             return 1;
97         return 0;
98 }
99
100 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
101 {
102     if (chainpp) {
103                 /* skip over null-terminated string */
104                 *chainpp = inp + strlen(inp) + 1;
105     }
106     return inp;
107 }   
108
109 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
110 {
111     char *tp;
112     char *usern, *pwd, *pwdx;
113     smb_user_t *uidp;
114     unsigned short newUid;
115     unsigned long caps;
116     cm_user_t *userp;
117     smb_username_t *unp;
118     char *s1 = " ";
119
120     /* Check for bad conns */
121     if (vcp->flags & SMB_VCFLAG_REMOTECONN)
122         return CM_ERROR_REMOTECONN;
123
124     /* For NT LM 0.12 and up, get capabilities */
125     if (vcp->flags & SMB_VCFLAG_USENT) {
126         caps = smb_GetSMBParm(inp, 11);
127         if (caps & 0x40)
128             vcp->flags |= SMB_VCFLAG_STATUS32;
129         /* for now, ignore other capability bits */
130     }
131
132     /* Parse the data */
133     tp = smb_GetSMBData(inp, NULL);
134     if (vcp->flags & SMB_VCFLAG_USENT)
135         pwdx = smb_ParseString(tp, &tp);
136     pwd = smb_ParseString(tp, &tp);
137     usern = smb_ParseString(tp, &tp);
138
139     /* On Windows 2000, this function appears to be called more often than
140        it is expected to be called. This resulted in multiple smb_user_t
141        records existing all for the same user session which results in all
142        of the users tokens disappearing.
143
144        To avoid this problem, we look for an existing smb_user_t record
145        based on the users name, and use that one if we find it.
146     */
147
148     uidp = smb_FindUserByNameThisSession(vcp, usern);
149     if (uidp) {   /* already there, so don't create a new one */
150         unp = uidp->unp;
151         userp = unp->userp;
152         newUid = (unsigned short)uidp->userID;  /* For some reason these are different types!*/
153                 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,usern);
154                 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
155         smb_ReleaseUID(uidp);
156     }
157     else {
158       /* do a global search for the username/machine name pair */
159         unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
160
161         /* Create a new UID and cm_user_t structure */
162         userp = unp->userp;
163         if (!userp)
164             userp = cm_NewUser();
165         lock_ObtainMutex(&vcp->mx);
166         if (!vcp->uidCounter)
167             vcp->uidCounter++; /* handle unlikely wraparounds */
168         newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
169         lock_ReleaseMutex(&vcp->mx);
170
171         /* Create a new smb_user_t structure and connect them up */
172         lock_ObtainMutex(&unp->mx);
173         unp->userp = userp;
174         lock_ReleaseMutex(&unp->mx);
175
176         uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
177         lock_ObtainMutex(&uidp->mx);
178         uidp->unp = unp;
179                 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",(int)vcp,vcp->lana,vcp->lsn,newUid,usern);
180                 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
181         lock_ReleaseMutex(&uidp->mx);
182         smb_ReleaseUID(uidp);
183     }
184
185     /* Return UID to the client */
186     ((smb_t *)outp)->uid = newUid;
187     /* Also to the next chained message */
188     ((smb_t *)inp)->uid = newUid;
189
190     osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
191              osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
192     smb_SetSMBParm(outp, 2, 0);
193     smb_SetSMBDataLength(outp, 0);
194     return 0;
195 }
196
197 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
198 {
199         smb_user_t *uidp;
200
201         /* don't get tokens from this VC */
202         vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
203
204         inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
205
206         /* find the tree and free it */
207     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
208     /* TODO: smb_ReleaseUID() ? */
209     if (uidp) {
210                 char *s1 = NULL, *s2 = NULL;
211
212                 if (s2 == NULL) s2 = " ";
213                 if (s1 == NULL) {s1 = s2; s2 = " ";}
214
215                 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s",
216                   uidp->userID,
217                   osi_LogSaveString(smb_logp,
218                                     (uidp->unp) ? uidp->unp->name: " "), s1, s2);
219
220                 lock_ObtainMutex(&uidp->mx);
221                 uidp->flags |= SMB_USERFLAG_DELETE;
222                 /*
223                  * it doesn't get deleted right away
224                  * because the vcp points to it
225                  */
226         lock_ReleaseMutex(&uidp->mx);
227     }
228         else    
229                 osi_Log0(smb_logp, "SMB3 user logoffX");
230
231     smb_SetSMBDataLength(outp, 0);
232     return 0;
233 }
234
235 #define SMB_SUPPORT_SEARCH_BITS        0x0001
236
237 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
238 {
239     smb_tid_t *tidp;
240     unsigned short newTid;
241     char shareName[256];
242         char *sharePath;
243         int shareFound;
244     char *tp;
245     char *pathp;
246     char *passwordp;
247         char *servicep;
248     cm_user_t *userp;
249         
250         osi_Log0(smb_logp, "SMB3 receive tree connect");
251
252         /* parse input parameters */
253         tp = smb_GetSMBData(inp, NULL);
254     passwordp = smb_ParseString(tp, &tp);
255         pathp = smb_ParseString(tp, &tp);
256         servicep = smb_ParseString(tp, &tp);
257
258         tp = strrchr(pathp, '\\');
259     if (!tp) {
260         return CM_ERROR_BADSMB;
261     }
262     strcpy(shareName, tp+1);
263
264         if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0)
265                 return CM_ERROR_NOIPC;
266
267     userp = smb_GetUser(vcp, inp);
268
269         lock_ObtainMutex(&vcp->mx);
270     newTid = vcp->tidCounter++;
271         lock_ReleaseMutex(&vcp->mx);
272         
273         tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
274         shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
275         if (!shareFound) {
276                 smb_ReleaseTID(tidp);
277                 return CM_ERROR_BADSHARENAME;
278         }
279     lock_ObtainMutex(&tidp->mx);
280     tidp->userp = userp;
281         tidp->pathname = sharePath;
282     lock_ReleaseMutex(&tidp->mx);
283     smb_ReleaseTID(tidp);
284
285         if (vcp->flags & SMB_VCFLAG_USENT)
286     {
287         int policy = smb_FindShareCSCPolicy(shareName);
288         smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy << 2));
289     }
290
291         ((smb_t *)outp)->tid = newTid;
292         ((smb_t *)inp)->tid = newTid;
293         tp = smb_GetSMBData(outp, NULL);
294     *tp++ = 'A';
295     *tp++ = ':';
296     *tp++ = 0;
297     smb_SetSMBDataLength(outp, 3);
298
299     osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
300     return 0;
301 }
302
303 /* must be called with global tran lock held */
304 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
305 {
306         smb_tran2Packet_t *tp;
307     smb_t *smbp;
308         
309     smbp = (smb_t *) inp->data;
310         for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
311                 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
312             return tp;
313     }
314     return NULL;
315 }
316
317 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
318         int totalParms, int totalData)
319 {
320         smb_tran2Packet_t *tp;
321     smb_t *smbp;
322         
323     smbp = (smb_t *) inp->data;
324         tp = malloc(sizeof(*tp));
325     memset(tp, 0, sizeof(*tp));
326     tp->vcp = vcp;
327     smb_HoldVC(vcp);
328     tp->curData = tp->curParms = 0;
329     tp->totalData = totalData;
330     tp->totalParms = totalParms;
331     tp->tid = smbp->tid;
332     tp->mid = smbp->mid;
333     tp->uid = smbp->uid;
334     tp->pid = smbp->pid;
335         tp->res[0] = smbp->res[0];
336         osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
337     tp->opcode = smb_GetSMBParm(inp, 14);
338         if (totalParms != 0)
339         tp->parmsp = malloc(totalParms);
340         if (totalData != 0)
341         tp->datap = malloc(totalData);
342         tp->flags |= SMB_TRAN2PFLAG_ALLOC;
343     return tp;
344 }
345
346 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
347         smb_tran2Packet_t *inp, smb_packet_t *outp,
348         int totalParms, int totalData)
349 {
350         smb_tran2Packet_t *tp;
351         unsigned short parmOffset;
352         unsigned short dataOffset;
353         unsigned short dataAlign;
354         
355         tp = malloc(sizeof(*tp));
356     memset(tp, 0, sizeof(*tp));
357     tp->vcp = NULL;
358     tp->curData = tp->curParms = 0;
359     tp->totalData = totalData;
360     tp->totalParms = totalParms;
361         tp->oldTotalParms = totalParms;
362     tp->tid = inp->tid;
363     tp->mid = inp->mid;
364     tp->uid = inp->uid;
365     tp->pid = inp->pid;
366         tp->res[0] = inp->res[0];
367     tp->opcode = inp->opcode;
368
369         /*
370          * We calculate where the parameters and data will start.
371          * This calculation must parallel the calculation in
372          * smb_SendTran2Packet.
373          */
374
375         parmOffset = 10*2 + 35;
376         parmOffset++;                   /* round to even */
377         tp->parmsp = (unsigned short *) (outp->data + parmOffset);
378
379         dataOffset = parmOffset + totalParms;
380         dataAlign = dataOffset & 2;     /* quad-align */
381         dataOffset += dataAlign;
382         tp->datap = outp->data + dataOffset;
383
384     return tp;
385 }
386
387 /* free a tran2 packet; must be called with smb_globalLock held */
388 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
389 {
390     if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
391         if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
392                 if (t2p->parmsp)
393                         free(t2p->parmsp);
394                 if (t2p->datap)
395                         free(t2p->datap);
396         }
397     free(t2p);
398 }
399
400 /* called with a VC, an input packet to respond to, and an error code.
401  * sends an error response.
402  */
403 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
404         smb_packet_t *tp, long code)
405 {
406     smb_t *smbp;
407     unsigned short errCode;
408     unsigned char errClass;
409         unsigned long NTStatus;
410
411     if (vcp->flags & SMB_VCFLAG_STATUS32)
412                 smb_MapNTError(code, &NTStatus);
413         else
414                 smb_MapCoreError(code, vcp, &errCode, &errClass);
415
416     smb_FormatResponsePacket(vcp, NULL, tp);
417     smbp = (smb_t *) tp;
418
419         /* We can handle long names */
420         if (vcp->flags & SMB_VCFLAG_USENT)
421                 smbp->flg2 |= 0x40;     /* IS_LONG_NAME */
422         
423     /* now copy important fields from the tran 2 packet */
424     smbp->com = 0x32;           /* tran 2 response */
425     smbp->tid = t2p->tid;
426     smbp->mid = t2p->mid;
427     smbp->pid = t2p->pid;
428     smbp->uid = t2p->uid;
429         smbp->res[0] = t2p->res[0];
430         if (vcp->flags & SMB_VCFLAG_STATUS32) {
431                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
432                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
433                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
434                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
435                 smbp->flg2 |= 0x4000;
436         }
437         else {
438         smbp->rcls = errClass;
439                 smbp->errLow = (unsigned char) (errCode & 0xff);
440                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
441         }
442         
443     /* send packet */
444     smb_SendPacket(vcp, tp);
445 }        
446
447 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
448 {
449     smb_t *smbp;
450     unsigned short parmOffset;
451         unsigned short dataOffset;
452         unsigned short totalLength;
453         unsigned short dataAlign;
454     char *datap;
455         
456     smb_FormatResponsePacket(vcp, NULL, tp);
457     smbp = (smb_t *) tp;
458
459         /* We can handle long names */
460         if (vcp->flags & SMB_VCFLAG_USENT)
461                 smbp->flg2 |= 0x40;     /* IS_LONG_NAME */
462
463     /* now copy important fields from the tran 2 packet */
464     smbp->com = 0x32;           /* tran 2 response */
465     smbp->tid = t2p->tid;
466     smbp->mid = t2p->mid;
467     smbp->pid = t2p->pid;
468     smbp->uid = t2p->uid;
469         smbp->res[0] = t2p->res[0];
470
471     totalLength = 1 + t2p->totalData + t2p->totalParms;
472
473     /* now add the core parameters (tran2 info) to the packet */
474     smb_SetSMBParm(tp, 0, t2p->totalParms);     /* parm bytes */
475     smb_SetSMBParm(tp, 1, t2p->totalData);      /* data bytes */
476     smb_SetSMBParm(tp, 2, 0);           /* reserved */
477     smb_SetSMBParm(tp, 3, t2p->totalParms);     /* parm bytes in this packet */
478         parmOffset = 10*2 + 35;                 /* parm offset in packet */
479         parmOffset++;                           /* round to even */
480     smb_SetSMBParm(tp, 4, parmOffset);  /* 11 parm words plus *
481     * hdr, bcc and wct */
482     smb_SetSMBParm(tp, 5, 0);           /* parm displacement */
483     smb_SetSMBParm(tp, 6, t2p->totalData);      /* data in this packet */
484         dataOffset = parmOffset + t2p->oldTotalParms;
485         dataAlign = dataOffset & 2;             /* quad-align */
486         dataOffset += dataAlign;
487     smb_SetSMBParm(tp, 7, dataOffset);  /* offset of data */
488     smb_SetSMBParm(tp, 8, 0);           /* data displacement */
489     smb_SetSMBParm(tp, 9, 0);           /* low: setup word count *
490     * high: resvd */
491
492     datap = smb_GetSMBData(tp, NULL);
493         *datap++ = 0;                           /* we rounded to even */
494
495         totalLength += dataAlign;
496     smb_SetSMBDataLength(tp, totalLength);
497         
498     /* next, send the datagram */
499     smb_SendPacket(vcp, tp);
500 }   
501
502 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
503 {
504     smb_tran2Packet_t *asp;
505     int totalParms;
506     int totalData;
507     int parmDisp;
508     int dataDisp;
509     int parmOffset;
510     int dataOffset;
511     int parmCount;
512     int dataCount;
513     int firstPacket;
514     long code = 0;
515
516         /* We sometimes see 0 word count.  What to do? */
517         if (*inp->wctp == 0) {
518 #ifndef DJGPP
519                 HANDLE h;
520                 char *ptbuf[1];
521
522                 osi_Log0(smb_logp, "TRANSACTION2 word count = 0"); 
523
524                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
525                 ptbuf[0] = "Transaction2 word count = 0";
526                 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
527                             1, inp->ncb_length, ptbuf, inp);
528                 DeregisterEventSource(h);
529 #else /* DJGPP */
530                 osi_Log0(smb_logp, "TRANSACTION2 word count = 0"); 
531 #endif /* !DJGPP */
532
533         smb_SetSMBDataLength(outp, 0);
534         smb_SendPacket(vcp, outp);
535                 return 0;
536         }
537
538     totalParms = smb_GetSMBParm(inp, 0);
539     totalData = smb_GetSMBParm(inp, 1);
540         
541     firstPacket = (inp->inCom == 0x32);
542         
543         /* find the packet we're reassembling */
544         lock_ObtainWrite(&smb_globalLock);
545     asp = smb_FindTran2Packet(vcp, inp);
546     if (!asp) {
547         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
548         }
549     lock_ReleaseWrite(&smb_globalLock);
550         
551     /* now merge in this latest packet; start by looking up offsets */
552         if (firstPacket) {
553                 parmDisp = dataDisp = 0;
554         parmOffset = smb_GetSMBParm(inp, 10);
555         dataOffset = smb_GetSMBParm(inp, 12);
556         parmCount = smb_GetSMBParm(inp, 9);
557         dataCount = smb_GetSMBParm(inp, 11);
558                 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
559         asp->maxReturnData = smb_GetSMBParm(inp, 3);
560
561                 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
562                  totalData, dataCount, asp->maxReturnData);
563     }
564     else {
565         parmDisp = smb_GetSMBParm(inp, 4);
566         parmOffset = smb_GetSMBParm(inp, 3);
567         dataDisp = smb_GetSMBParm(inp, 7);
568         dataOffset = smb_GetSMBParm(inp, 6);
569         parmCount = smb_GetSMBParm(inp, 2);
570         dataCount = smb_GetSMBParm(inp, 5);
571
572         osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
573                  parmCount, dataCount);
574     }   
575
576     /* now copy the parms and data */
577     if ( parmCount != 0 )
578     {
579         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
580     }
581     if ( dataCount != 0 ) {
582         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
583     }
584
585     /* account for new bytes */
586     asp->curData += dataCount;
587     asp->curParms += parmCount;
588
589     /* finally, if we're done, remove the packet from the queue and dispatch it */
590     if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
591                 /* we've received it all */
592         lock_ObtainWrite(&smb_globalLock);
593                 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
594         lock_ReleaseWrite(&smb_globalLock);
595
596         /* now dispatch it */
597         if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
598             osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
599             osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
600             code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
601         }
602         else {
603             osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
604             osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
605             code = CM_ERROR_BADOP;
606         }
607
608                 /* if an error is returned, we're supposed to send an error packet,
609          * otherwise the dispatched function already did the data sending.
610          * We give dispatched proc the responsibility since it knows how much
611          * space to allocate.
612          */
613         if (code != 0) {
614             smb_SendTran2Error(vcp, asp, outp, code);
615         }
616
617                 /* free the input tran 2 packet */
618                 lock_ObtainWrite(&smb_globalLock);
619         smb_FreeTran2Packet(asp);
620                 lock_ReleaseWrite(&smb_globalLock);
621     }
622     else if (firstPacket) {
623                 /* the first packet in a multi-packet request, we need to send an
624          * ack to get more data.
625          */
626         smb_SetSMBDataLength(outp, 0);
627         smb_SendPacket(vcp, outp);
628     }
629
630         return 0;
631 }
632
633 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
634 {
635         char *pathp;
636     smb_tran2Packet_t *outp;
637     long code = 0;
638         cm_space_t *spacep;
639     int excl;
640     cm_user_t *userp;
641     cm_scache_t *dscp;          /* dir we're dealing with */
642     cm_scache_t *scp;           /* file we're creating */
643     cm_attr_t setAttr;
644     int initialModeBits;
645     smb_fid_t *fidp;
646     int attributes;
647     char *lastNamep;
648     long dosTime;
649     int openFun;
650     int trunc;
651     int openMode;
652     int extraInfo;
653     int openAction;
654     int parmSlot;                       /* which parm we're dealing with */
655     long returnEALength;
656         char *tidPathp;
657         cm_req_t req;
658
659         cm_InitReq(&req);
660
661     scp = NULL;
662         
663         extraInfo = (p->parmsp[0] & 1); /* return extra info */
664     returnEALength = (p->parmsp[0] & 8);        /* return extended attr length */
665
666         openFun = p->parmsp[6];         /* open function */
667     excl = ((openFun & 3) == 0);
668     trunc = ((openFun & 3) == 2);       /* truncate it */
669         openMode = (p->parmsp[1] & 0x7);
670     openAction = 0;                     /* tracks what we did */
671
672     attributes = p->parmsp[3];
673     dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
674         
675         /* compute initial mode bits based on read-only flag in attributes */
676     initialModeBits = 0666;
677     if (attributes & 1) initialModeBits &= ~0222;
678         
679     pathp = (char *) (&p->parmsp[14]);
680         
681     outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
682
683         spacep = cm_GetSpace();
684     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
685
686         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
687                 /* special case magic file name for receiving IOCTL requests
688          * (since IOCTL calls themselves aren't getting through).
689          */
690         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
691         smb_SetupIoctlFid(fidp, spacep);
692
693         /* copy out remainder of the parms */
694                 parmSlot = 0;
695                 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
696                 if (extraInfo) {
697             outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
698             outp->parmsp[parmSlot] = 0; parmSlot++;     /* mod time */
699             outp->parmsp[parmSlot] = 0; parmSlot++;
700             outp->parmsp[parmSlot] = 0; parmSlot++;     /* len */
701             outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
702             outp->parmsp[parmSlot] = openMode; parmSlot++;
703             outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
704             outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
705                 }   
706                 /* and the final "always present" stuff */
707         outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
708                 /* next write out the "unique" ID */
709                 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
710                 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
711         outp->parmsp[parmSlot] = 0; parmSlot++;
712                 if (returnEALength) {
713                         outp->parmsp[parmSlot] = 0; parmSlot++;
714                         outp->parmsp[parmSlot] = 0; parmSlot++;
715         }
716                 
717         outp->totalData = 0;
718         outp->totalParms = parmSlot * 2;
719                 
720         smb_SendTran2Packet(vcp, outp, op);
721                 
722         smb_FreeTran2Packet(outp);
723
724                 /* and clean up fid reference */
725         smb_ReleaseFID(fidp);
726         return 0;
727     }
728
729 #ifdef DEBUG_VERBOSE
730         {
731                 char *hexp, *asciip;
732                 asciip = (lastNamep ? lastNamep : pathp);
733                 hexp = osi_HexifyString( asciip );
734                 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
735                 free(hexp);
736         }
737 #endif
738
739         userp = smb_GetTran2User(vcp, p);
740     /* In the off chance that userp is NULL, we log and abandon */
741     if(!userp) {
742         osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
743         smb_FreeTran2Packet(outp);
744         return CM_ERROR_BADSMB;
745     }
746
747         tidPathp = smb_GetTIDPath(vcp, p->tid);
748
749         dscp = NULL;
750         code = cm_NameI(cm_rootSCachep, pathp,
751                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
752                     userp, tidPathp, &req, &scp);
753         if (code != 0) {
754                 code = cm_NameI(cm_rootSCachep, spacep->data,
755                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
756                         userp, tidPathp, &req, &dscp);
757                 cm_FreeSpace(spacep);
758
759         if (code) {
760             cm_ReleaseUser(userp);
761                         smb_FreeTran2Packet(outp);
762             return code;
763         }
764         
765         /* otherwise, scp points to the parent directory.  Do a lookup,
766                  * and truncate the file if we find it, otherwise we create the
767                  * file.
768          */
769         if (!lastNamep) lastNamep = pathp;
770         else lastNamep++;
771         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
772                          &req, &scp);
773         if (code && code != CM_ERROR_NOSUCHFILE) {
774                         cm_ReleaseSCache(dscp);
775             cm_ReleaseUser(userp);
776                         smb_FreeTran2Packet(outp);
777             return code;
778         }
779         }
780     else {
781         cm_FreeSpace(spacep);
782         }
783         
784     /* if we get here, if code is 0, the file exists and is represented by
785      * scp.  Otherwise, we have to create it.
786      */
787         if (code == 0) {
788         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
789         if (code) {
790             if (dscp) cm_ReleaseSCache(dscp);
791             cm_ReleaseSCache(scp);
792             cm_ReleaseUser(userp);
793                         smb_FreeTran2Packet(outp);
794             return code;
795         }
796
797                 if (excl) {
798                         /* oops, file shouldn't be there */
799             if (dscp) cm_ReleaseSCache(dscp);
800             cm_ReleaseSCache(scp);
801             cm_ReleaseUser(userp);
802                         smb_FreeTran2Packet(outp);
803             return CM_ERROR_EXISTS;
804         }
805
806                 if (trunc) {
807                         setAttr.mask = CM_ATTRMASK_LENGTH;
808             setAttr.length.LowPart = 0;
809             setAttr.length.HighPart = 0;
810                         code = cm_SetAttr(scp, &setAttr, userp, &req);
811             openAction = 3;     /* truncated existing file */
812                 }   
813         else openAction = 1;    /* found existing file */
814     }
815         else if (!(openFun & SMB_ATTR_DIRECTORY)) {
816                 /* don't create if not found */
817         if (dscp) cm_ReleaseSCache(dscp);
818         osi_assert(scp == NULL);
819         cm_ReleaseUser(userp);
820                 smb_FreeTran2Packet(outp);
821         return CM_ERROR_NOSUCHFILE;
822     }
823     else {
824                 osi_assert(dscp != NULL && scp == NULL);
825                 openAction = 2; /* created file */
826                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
827                 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
828         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
829                          &req);
830                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
831                         smb_NotifyChange(FILE_ACTION_ADDED,
832                              FILE_NOTIFY_CHANGE_FILE_NAME,  
833                              dscp, lastNamep, NULL, TRUE);
834         if (!excl && code == CM_ERROR_EXISTS) {
835                         /* not an exclusive create, and someone else tried
836                          * creating it already, then we open it anyway.  We
837                          * don't bother retrying after this, since if this next
838                          * fails, that means that the file was deleted after we
839                          * started this call.
840              */
841             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
842                              userp, &req, &scp);
843             if (code == 0) {
844                 if (trunc) {
845                                         setAttr.mask = CM_ATTRMASK_LENGTH;
846                     setAttr.length.LowPart = 0;
847                     setAttr.length.HighPart = 0;
848                     code = cm_SetAttr(scp, &setAttr, userp,
849                                       &req);
850                 }   
851                         }       /* lookup succeeded */
852         }
853     }
854         
855         /* we don't need this any longer */
856         if (dscp) cm_ReleaseSCache(dscp);
857
858     if (code) {
859                 /* something went wrong creating or truncating the file */
860         if (scp) cm_ReleaseSCache(scp);
861         cm_ReleaseUser(userp);
862                 smb_FreeTran2Packet(outp);
863         return code;
864     }
865         
866         /* make sure we're about to open a file */
867         if (scp->fileType != CM_SCACHETYPE_FILE) {
868                 cm_ReleaseSCache(scp);
869                 cm_ReleaseUser(userp);
870                 smb_FreeTran2Packet(outp);
871                 return CM_ERROR_ISDIR;
872         }
873
874     /* now all we have to do is open the file itself */
875     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
876     osi_assert(fidp);
877         
878         /* save a pointer to the vnode */
879     fidp->scp = scp;
880         
881         /* compute open mode */
882     if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
883     if (openMode == 1 || openMode == 2)
884         fidp->flags |= SMB_FID_OPENWRITE;
885
886         smb_ReleaseFID(fidp);
887         
888         cm_Open(scp, 0, userp);
889
890     /* copy out remainder of the parms */
891         parmSlot = 0;
892         outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
893         lock_ObtainMutex(&scp->mx);
894         if (extraInfo) {
895         outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
896                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
897         outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
898         outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
899         outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
900         parmSlot++;
901         outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
902         parmSlot++;
903         outp->parmsp[parmSlot] = openMode; parmSlot++;
904         outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
905         outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
906         }   
907         /* and the final "always present" stuff */
908     outp->parmsp[parmSlot] = openAction; parmSlot++;
909         /* next write out the "unique" ID */
910         outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
911         outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
912     outp->parmsp[parmSlot] = 0; parmSlot++;
913     if (returnEALength) {
914                 outp->parmsp[parmSlot] = 0; parmSlot++;
915                 outp->parmsp[parmSlot] = 0; parmSlot++;
916     }
917         lock_ReleaseMutex(&scp->mx);
918         outp->totalData = 0;            /* total # of data bytes */
919     outp->totalParms = parmSlot * 2;    /* shorts are two bytes */
920
921         smb_SendTran2Packet(vcp, outp, op);
922         
923     smb_FreeTran2Packet(outp);
924
925     cm_ReleaseUser(userp);
926     /* leave scp held since we put it in fidp->scp */
927     return 0;
928 }   
929
930 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
931 {
932     return CM_ERROR_BADOP;
933 }
934
935 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
936 {
937     return CM_ERROR_BADOP;
938 }
939
940 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
941 {
942         smb_tran2Packet_t *outp;
943     smb_tran2QFSInfo_t qi;
944         int responseSize;
945         osi_hyper_t temp;
946         static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
947         
948         osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
949
950         switch (p->parmsp[0]) {
951         case 1: responseSize = sizeof(qi.u.allocInfo); break;
952         case 2: responseSize = sizeof(qi.u.volumeInfo); break;
953         case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
954         case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
955         case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
956         case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
957         default: return CM_ERROR_INVAL;
958         }
959
960     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
961         switch (p->parmsp[0]) {
962         case 1:
963                 /* alloc info */
964         qi.u.allocInfo.FSID = 0;
965         qi.u.allocInfo.sectorsPerAllocUnit = 1;
966         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
967         qi.u.allocInfo.availAllocUnits = 0x3fffffff;
968         qi.u.allocInfo.bytesPerSector = 1024;
969                 break;
970
971     case 2:
972                 /* volume info */
973         qi.u.volumeInfo.vsn = 1234;
974         qi.u.volumeInfo.vnCount = 4;
975                 /* we're supposed to pad it out with zeroes to the end */
976                 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
977         memcpy(qi.u.volumeInfo.label, "AFS", 4);
978                 break;
979
980         case 0x102:
981                 /* FS volume info */
982                 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
983                 qi.u.FSvolumeInfo.vsn = 1234;
984                 qi.u.FSvolumeInfo.vnCount = 8;
985                 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
986                 break;
987
988         case 0x103:
989                 /* FS size info */
990                 temp.HighPart = 0;
991                 temp.LowPart = 0x7fffffff;
992                 qi.u.FSsizeInfo.totalAllocUnits = temp;
993                 temp.LowPart = 0x3fffffff;
994                 qi.u.FSsizeInfo.availAllocUnits = temp;
995                 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
996                 qi.u.FSsizeInfo.bytesPerSector = 1024;
997                 break;
998
999         case 0x104:
1000                 /* FS device info */
1001                 qi.u.FSdeviceInfo.devType = 0;  /* don't have a number */
1002                 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
1003                 break;
1004
1005         case 0x105:
1006                 /* FS attribute info */
1007                 /* attributes, defined in WINNT.H:
1008                  *      FILE_CASE_SENSITIVE_SEARCH      0x1
1009                  *      FILE_CASE_PRESERVED_NAMES       0x2
1010                  *      <no name defined>               0x4000
1011                  *         If bit 0x4000 is not set, Windows 95 thinks
1012                  *         we can't handle long (non-8.3) names,
1013                  *         despite our protestations to the contrary.
1014                  */
1015                 qi.u.FSattributeInfo.attributes = 0x4003;
1016                 qi.u.FSattributeInfo.maxCompLength = 255;
1017                 qi.u.FSattributeInfo.FSnameLength = 6;
1018                 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
1019                 break;
1020     }
1021         
1022         /* copy out return data, and set corresponding sizes */
1023         outp->totalParms = 0;
1024     outp->totalData = responseSize;
1025     memcpy(outp->datap, &qi, responseSize);
1026
1027         /* send and free the packets */
1028         smb_SendTran2Packet(vcp, outp, op);
1029     smb_FreeTran2Packet(outp);
1030
1031     return 0;
1032 }
1033
1034 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1035 {
1036     return CM_ERROR_BADOP;
1037 }
1038
1039 struct smb_ShortNameRock {
1040         char *maskp;
1041         unsigned int vnode;
1042         char *shortName;
1043         size_t shortNameLen;
1044 };
1045
1046 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
1047         osi_hyper_t *offp)
1048 {
1049         struct smb_ShortNameRock *rockp;
1050         char *shortNameEnd;
1051
1052         rockp = vrockp;
1053         /* compare both names and vnodes, though probably just comparing vnodes
1054          * would be safe enough.
1055          */
1056         if (cm_stricmp(dep->name, rockp->maskp) != 0)
1057                 return 0;
1058         if (ntohl(dep->fid.vnode) != rockp->vnode)
1059                 return 0;
1060         /* This is the entry */
1061         cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1062         rockp->shortNameLen = shortNameEnd - rockp->shortName;
1063         return CM_ERROR_STOPNOW;
1064 }
1065
1066 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1067         char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1068 {
1069         struct smb_ShortNameRock rock;
1070         char *lastNamep;
1071         cm_space_t *spacep;
1072         cm_scache_t *dscp;
1073         int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1074         long code = 0;
1075         osi_hyper_t thyper;
1076
1077         spacep = cm_GetSpace();
1078         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1079
1080         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1081                      reqp, &dscp);
1082         cm_FreeSpace(spacep);
1083         if (code) return code;
1084
1085         if (!lastNamep) lastNamep = pathp;
1086         else lastNamep++;
1087         thyper.LowPart = 0;
1088         thyper.HighPart = 0;
1089         rock.shortName = shortName;
1090         rock.vnode = vnode;
1091         rock.maskp = lastNamep;
1092         code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1093                         reqp, NULL);
1094
1095         cm_ReleaseSCache(dscp);
1096
1097         if (code == 0)
1098                 return CM_ERROR_NOSUCHFILE;
1099         if (code == CM_ERROR_STOPNOW) {
1100                 *shortNameLenp = rock.shortNameLen;
1101                 return 0;
1102         }
1103         return code;
1104 }
1105
1106 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1107 {
1108         smb_tran2Packet_t *outp;
1109     unsigned long dosTime;
1110         FILETIME ft;
1111     unsigned short infoLevel;
1112     int nbytesRequired;
1113     unsigned short attributes;
1114         unsigned long extAttributes;
1115         char shortName[13];
1116         unsigned int len;
1117     cm_user_t *userp;
1118         cm_space_t *spacep;
1119     cm_scache_t *scp, *dscp;
1120     long code = 0;
1121     char *op;
1122         char *tidPathp;
1123         char *lastComp;
1124         cm_req_t req;
1125
1126         cm_InitReq(&req);
1127
1128         infoLevel = p->parmsp[0];
1129     if (infoLevel == 6) nbytesRequired = 0;
1130     else if (infoLevel == 1) nbytesRequired = 22;
1131     else if (infoLevel == 2) nbytesRequired = 26;
1132         else if (infoLevel == 0x101) nbytesRequired = 40;
1133         else if (infoLevel == 0x102) nbytesRequired = 24;
1134         else if (infoLevel == 0x103) nbytesRequired = 4;
1135         else if (infoLevel == 0x108) nbytesRequired = 30;
1136     else {
1137                 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1138                   p->opcode, infoLevel);
1139                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1140         return 0;
1141     }
1142         osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1143              osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
1144
1145     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1146
1147         if (infoLevel > 0x100)
1148                 outp->totalParms = 2;
1149         else
1150                 outp->totalParms = 0;
1151         outp->totalData = nbytesRequired;
1152         
1153     /* now, if we're at infoLevel 6, we're only being asked to check
1154      * the syntax, so we just OK things now.  In particular, we're *not*
1155      * being asked to verify anything about the state of any parent dirs.
1156      */
1157         if (infoLevel == 6) {
1158                 smb_SendTran2Packet(vcp, outp, opx);
1159         smb_FreeTran2Packet(outp);
1160                 return 0;
1161     }
1162         
1163     userp = smb_GetTran2User(vcp, p);
1164     if(!userp) {
1165         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
1166         smb_FreeTran2Packet(outp);
1167         return CM_ERROR_BADSMB;
1168     }
1169
1170         tidPathp = smb_GetTIDPath(vcp, p->tid);
1171
1172         /*
1173          * XXX Strange hack XXX
1174          *
1175          * As of Patch 7 (13 January 98), we are having the following problem:
1176          * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1177          * requests to look up "desktop.ini" in all the subdirectories.
1178          * This can cause zillions of timeouts looking up non-existent cells
1179          * and volumes, especially in the top-level directory.
1180          *
1181          * We have not found any way to avoid this or work around it except
1182          * to explicitly ignore the requests for mount points that haven't
1183          * yet been evaluated and for directories that haven't yet been
1184          * fetched.
1185          */
1186         if (infoLevel == 0x101) {
1187                 spacep = cm_GetSpace();
1188                 smb_StripLastComponent(spacep->data, &lastComp,
1189                                         (char *)(&p->parmsp[3]));
1190                 /* Make sure that lastComp is not NULL */
1191                 if (lastComp) {
1192                     if (strcmp(lastComp, "\\desktop.ini") == 0) {
1193                 code = cm_NameI(cm_rootSCachep, spacep->data,
1194                                 CM_FLAG_CASEFOLD
1195                                 | CM_FLAG_DIRSEARCH
1196                                 | CM_FLAG_FOLLOW,
1197                                 userp, tidPathp, &req, &dscp);
1198                 if (code == 0) {
1199                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1200                          && !dscp->mountRootFidp)
1201                         code = CM_ERROR_NOSUCHFILE;
1202                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1203                         cm_buf_t *bp = buf_Find(dscp, &hzero);
1204                         if (bp)
1205                             buf_Release(bp);
1206                         else
1207                             code = CM_ERROR_NOSUCHFILE;
1208                     }
1209                     cm_ReleaseSCache(dscp);
1210                     if (code) {
1211                         cm_FreeSpace(spacep);
1212                         cm_ReleaseUser(userp);
1213                         smb_SendTran2Error(vcp, p, opx, code);
1214                         smb_FreeTran2Packet(outp);
1215                         return 0;
1216                     }
1217                 }
1218             }
1219         }
1220                 cm_FreeSpace(spacep);
1221         }
1222
1223         /* now do namei and stat, and copy out the info */
1224     code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1225                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1226
1227         if (code) {
1228                 cm_ReleaseUser(userp);
1229         smb_SendTran2Error(vcp, p, opx, code);
1230         smb_FreeTran2Packet(outp);
1231         return 0;
1232     }
1233
1234     lock_ObtainMutex(&scp->mx);
1235         code = cm_SyncOp(scp, NULL, userp, &req, 0,
1236                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1237         if (code) goto done;
1238         
1239     /* now we have the status in the cache entry, and everything is locked.
1240          * Marshall the output data.
1241      */
1242         op = outp->datap;
1243         /* for info level 108, figure out short name */
1244         if (infoLevel == 0x108) {
1245                 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1246                                 tidPathp, scp->fid.vnode, shortName,
1247                                 (size_t *) &len);
1248                 if (code) {
1249                         goto done;
1250                 }
1251
1252                 op = outp->datap;
1253                 *((u_long *)op) = len * 2; op += 4;
1254                 mbstowcs((unsigned short *)op, shortName, len);
1255                 op += (len * 2);
1256
1257                 goto done;
1258         }
1259         if (infoLevel == 1 || infoLevel == 2) {
1260                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1261         *((u_long *)op) = dosTime; op += 4;     /* creation time */
1262         *((u_long *)op) = dosTime; op += 4;     /* access time */
1263         *((u_long *)op) = dosTime; op += 4;     /* write time */
1264         *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1265         *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1266                 attributes = smb_Attributes(scp);
1267                 *((u_short *)op) = attributes; op += 2; /* attributes */
1268         }
1269         else if (infoLevel == 0x101) {
1270                 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1271                 *((FILETIME *)op) = ft; op += 8;        /* creation time */
1272                 *((FILETIME *)op) = ft; op += 8;        /* last access time */
1273                 *((FILETIME *)op) = ft; op += 8;        /* last write time */
1274                 *((FILETIME *)op) = ft; op += 8;        /* last change time */
1275                 extAttributes = smb_ExtAttributes(scp);
1276                 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1277                 *((u_long *)op) = 0; op += 4;   /* don't know what this is */
1278         }
1279         else if (infoLevel == 0x102) {
1280                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
1281                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
1282                 *((u_long *)op) = scp->linkCount; op += 4;
1283                 *op++ = 0;
1284                 *op++ = 0;
1285                 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1286                 *op++ = 0;
1287         }
1288         else if (infoLevel == 0x103) {
1289                 memset(op, 0, 4); op += 4;      /* EA size */
1290         }
1291
1292         /* now, if we are being asked about extended attrs, return a 0 size */
1293         if (infoLevel == 2) {
1294                 *((u_long *)op) = 0; op += 4;
1295         }
1296         
1297
1298         /* send and free the packets */
1299   done:
1300         lock_ReleaseMutex(&scp->mx);
1301     cm_ReleaseSCache(scp);
1302     cm_ReleaseUser(userp);
1303         if (code == 0) 
1304         smb_SendTran2Packet(vcp, outp, opx);
1305     else 
1306         smb_SendTran2Error(vcp, p, opx, code);
1307     smb_FreeTran2Packet(outp);
1308
1309     return 0;
1310 }
1311
1312 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1313 {
1314     return CM_ERROR_BADOP;
1315 }
1316
1317 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1318 {
1319         smb_tran2Packet_t *outp;
1320         FILETIME ft;
1321         unsigned long attributes;
1322         unsigned short infoLevel;
1323         int nbytesRequired;
1324         unsigned short fid;
1325         cm_user_t *userp;
1326     smb_fid_t *fidp;
1327         cm_scache_t *scp;
1328         char *op;
1329         long code = 0;
1330         cm_req_t req;
1331
1332         cm_InitReq(&req);
1333
1334     fid = p->parmsp[0];
1335     fidp = smb_FindFID(vcp, fid, 0);
1336
1337         if (fidp == NULL) {
1338                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
1339                 return 0;
1340         }
1341
1342         infoLevel = p->parmsp[1];
1343         if (infoLevel == 0x101) nbytesRequired = 40;
1344         else if (infoLevel == 0x102) nbytesRequired = 24;
1345         else if (infoLevel == 0x103) nbytesRequired = 4;
1346         else if (infoLevel == 0x104) nbytesRequired = 6;
1347         else {
1348                 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1349                  p->opcode, infoLevel);
1350                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1351         smb_ReleaseFID(fidp);
1352                 return 0;
1353         }
1354         osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1355
1356         outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1357
1358         if (infoLevel > 0x100)
1359                 outp->totalParms = 2;
1360         else
1361                 outp->totalParms = 0;
1362         outp->totalData = nbytesRequired;
1363
1364         userp = smb_GetTran2User(vcp, p);
1365     if(!userp) {
1366         osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
1367         code = CM_ERROR_BADSMB;
1368         goto done;
1369     }
1370
1371         scp = fidp->scp;
1372         lock_ObtainMutex(&scp->mx);
1373         code = cm_SyncOp(scp, NULL, userp, &req, 0,
1374                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1375         if (code) goto done;
1376
1377         /* now we have the status in the cache entry, and everything is locked.
1378          * Marshall the output data.
1379          */
1380         op = outp->datap;
1381         if (infoLevel == 0x101) {
1382                 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1383                 *((FILETIME *)op) = ft; op += 8;        /* creation time */
1384                 *((FILETIME *)op) = ft; op += 8;        /* last access time */
1385                 *((FILETIME *)op) = ft; op += 8;        /* last write time */
1386                 *((FILETIME *)op) = ft; op += 8;        /* last change time */
1387                 attributes = smb_ExtAttributes(scp);
1388                 *((u_long *)op) = attributes; op += 4;
1389                 *((u_long *)op) = 0; op += 4;
1390         }
1391         else if (infoLevel == 0x102) {
1392                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
1393                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
1394                 *((u_long *)op) = scp->linkCount; op += 4;
1395                 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1396                 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1397                 *op++ = 0;
1398                 *op++ = 0;
1399         }
1400         else if (infoLevel == 0x103) {
1401                 *((u_long *)op) = 0; op += 4;
1402         }
1403         else if (infoLevel == 0x104) {
1404                 unsigned long len;
1405                 char *name;
1406
1407                 if (fidp->NTopen_wholepathp)
1408                         name = fidp->NTopen_wholepathp;
1409                 else
1410                         name = "\\";    /* probably can't happen */
1411                 len = strlen(name);
1412                 outp->totalData = (len*2) + 4;  /* this is actually what we want to return */
1413                 *((u_long *)op) = len * 2; op += 4;
1414                 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1415         }
1416
1417         /* send and free the packets */
1418   done:
1419         lock_ReleaseMutex(&scp->mx);
1420         cm_ReleaseUser(userp);
1421         smb_ReleaseFID(fidp);
1422         if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1423         else smb_SendTran2Error(vcp, p, opx, code);
1424         smb_FreeTran2Packet(outp);
1425
1426         return 0;
1427 }
1428
1429 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1430 {
1431         long code = 0;
1432         unsigned short fid;
1433         smb_fid_t *fidp;
1434         unsigned short infoLevel;
1435         smb_tran2Packet_t *outp;
1436         cm_user_t *userp;
1437         cm_scache_t *scp;
1438         cm_req_t req;
1439
1440         cm_InitReq(&req);
1441
1442     fid = p->parmsp[0];
1443         fidp = smb_FindFID(vcp, fid, 0);
1444
1445         if (fidp == NULL) {
1446                 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1447                 return 0;
1448         }
1449
1450         infoLevel = p->parmsp[1];
1451         if (infoLevel > 0x104 || infoLevel < 0x101) {
1452                 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1453                          p->opcode, infoLevel);
1454                 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1455         smb_ReleaseFID(fidp);
1456                 return 0;
1457         }
1458
1459         if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1460                 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1461         smb_ReleaseFID(fidp);
1462                 return 0;
1463         }
1464         if ((infoLevel == 0x103 || infoLevel == 0x104)
1465             && !(fidp->flags & SMB_FID_OPENWRITE)) {
1466                 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1467         smb_ReleaseFID(fidp);
1468                 return 0;
1469         }
1470
1471         osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
1472
1473         outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1474
1475         outp->totalParms = 2;
1476         outp->totalData = 0;
1477
1478         userp = smb_GetTran2User(vcp, p);
1479     if(!userp) {
1480         osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
1481         code = CM_ERROR_BADSMB;
1482         goto done;
1483     }
1484
1485         scp = fidp->scp;
1486
1487         if (infoLevel == 0x101) {
1488                 FILETIME lastMod;
1489                 unsigned int attribute;
1490                 cm_attr_t attr;
1491
1492                 /* lock the vnode with a callback; we need the current status
1493                  * to determine what the new status is, in some cases.
1494                  */
1495                 lock_ObtainMutex(&scp->mx);
1496                 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1497                          CM_SCACHESYNC_GETSTATUS
1498                          | CM_SCACHESYNC_NEEDCALLBACK);
1499                 if (code) {
1500                         lock_ReleaseMutex(&scp->mx);
1501                         goto done;
1502                 }
1503
1504                 /* prepare for setattr call */
1505                 attr.mask = 0;
1506                 
1507                 lastMod = *((FILETIME *)(p->datap + 16));
1508                 /* when called as result of move a b, lastMod is (-1, -1). 
1509          * If the check for -1 is not present, timestamp
1510                  * of the resulting file will be 1969 (-1)
1511                  */
1512                 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && 
1513             lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
1514                         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1515                         smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1516                                                         &lastMod);
1517                         fidp->flags |= SMB_FID_MTIMESETDONE;
1518                 }
1519                 
1520                 attribute = *((u_long *)(p->datap + 32));
1521                 if (attribute != 0) {
1522                         if ((scp->unixModeBits & 0222)
1523                             && (attribute & 1) != 0) {
1524                                 /* make a writable file read-only */
1525                                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1526                                 attr.unixModeBits = scp->unixModeBits & ~0222;
1527                         }
1528                         else if ((scp->unixModeBits & 0222) == 0
1529                                  && (attribute & 1) == 0) {
1530                                 /* make a read-only file writable */
1531                                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1532                                 attr.unixModeBits = scp->unixModeBits | 0222;
1533                         }
1534                 }
1535                 lock_ReleaseMutex(&scp->mx);
1536
1537                 /* call setattr */
1538                 if (attr.mask)
1539                         code = cm_SetAttr(scp, &attr, userp, &req);
1540                 else
1541                         code = 0;
1542         }
1543         else if (infoLevel == 0x103 || infoLevel == 0x104) {
1544                 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1545                 cm_attr_t attr;
1546
1547                 attr.mask = CM_ATTRMASK_LENGTH;
1548                 attr.length.LowPart = size.LowPart;
1549                 attr.length.HighPart = size.HighPart;
1550                 code = cm_SetAttr(scp, &attr, userp, &req);
1551         }
1552         else if (infoLevel == 0x102) {
1553                 if (*((char *)(p->datap))) {
1554                         code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1555                                                 &req);
1556                         if (code == 0)
1557                                 fidp->flags |= SMB_FID_DELONCLOSE;
1558                 }
1559                 else {
1560                         code = 0;
1561                         fidp->flags &= ~SMB_FID_DELONCLOSE;
1562                 }
1563         }
1564   done:
1565         cm_ReleaseUser(userp);
1566         smb_ReleaseFID(fidp);
1567         if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1568         else smb_SendTran2Error(vcp, p, op, code);
1569         smb_FreeTran2Packet(outp);
1570
1571         return 0;
1572 }
1573
1574 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1575 {
1576     return CM_ERROR_BADOP;
1577 }
1578
1579 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1580 {
1581     return CM_ERROR_BADOP;
1582 }
1583
1584 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1585 {
1586     return CM_ERROR_BADOP;
1587 }
1588
1589 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1590 {
1591     return CM_ERROR_BADOP;
1592 }
1593
1594 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1595 {
1596     return CM_ERROR_BADOP;
1597 }
1598
1599 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1600         smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1601         cm_req_t *reqp)
1602 {
1603         long code = 0;
1604     cm_scache_t *scp;
1605     cm_scache_t *targetScp;                     /* target if scp is a symlink */
1606     char *dptr;
1607     long dosTime;
1608         FILETIME ft;
1609     int shortTemp;
1610     unsigned short attr;
1611         unsigned long lattr;
1612     smb_dirListPatch_t *patchp;
1613     smb_dirListPatch_t *npatchp;
1614         
1615     for(patchp = *dirPatchespp; patchp; patchp =
1616          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1617                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1618         if (code) continue;
1619         lock_ObtainMutex(&scp->mx);
1620         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1621                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1622                 if (code) { 
1623                         lock_ReleaseMutex(&scp->mx);
1624                         cm_ReleaseSCache(scp);
1625                         continue;
1626         }
1627                 
1628         /* now watch for a symlink */
1629         if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1630                         lock_ReleaseMutex(&scp->mx);
1631             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
1632             if (code == 0) {
1633                                 /* we have a more accurate file to use (the
1634                                  * target of the symbolic link).  Otherwise,
1635                                  * we'll just use the symlink anyway.
1636                  */
1637                                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
1638                          scp, targetScp);
1639                                 cm_ReleaseSCache(scp);
1640                 scp = targetScp;
1641             }
1642             lock_ObtainMutex(&scp->mx);
1643         }
1644
1645                 dptr = patchp->dptr;
1646
1647                 if (infoLevel >= 0x101) {
1648                         /* get filetime */
1649                         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1650
1651                         /* copy to Creation Time */
1652                         *((FILETIME *)dptr) = ft;
1653                         dptr += 8;
1654
1655                         /* copy to Last Access Time */
1656                         *((FILETIME *)dptr) = ft;
1657                         dptr += 8;
1658
1659                         /* copy to Last Write Time */
1660                         *((FILETIME *)dptr) = ft;
1661                         dptr += 8;
1662
1663                         /* copy to Change Time */
1664                         *((FILETIME *)dptr) = ft;
1665                         dptr += 8;
1666
1667                         /* Use length for both file length and alloc length */
1668                         *((LARGE_INTEGER *)dptr) = scp->length;
1669                         dptr += 8;
1670                         *((LARGE_INTEGER *)dptr) = scp->length;
1671                         dptr += 8;
1672
1673                         /* Copy attributes */
1674                         lattr = smb_ExtAttributes(scp);
1675             /* merge in hidden (dot file) attribute */
1676                         if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1677                                 lattr |= SMB_ATTR_HIDDEN;
1678                         *((u_long *)dptr) = lattr;
1679                         dptr += 4;
1680                 }
1681                 else {
1682                         /* get dos time */
1683                         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1684
1685                         /* and copy out date */
1686                         shortTemp = (dosTime>>16) & 0xffff;
1687                         *((u_short *)dptr) = shortTemp;
1688                         dptr += 2;
1689
1690                         /* copy out creation time */
1691                         shortTemp = dosTime & 0xffff;
1692                         *((u_short *)dptr) = shortTemp;
1693                         dptr += 2;
1694
1695                         /* and copy out date */
1696                         shortTemp = (dosTime>>16) & 0xffff;
1697                         *((u_short *)dptr) = shortTemp;
1698                         dptr += 2;
1699                         
1700                         /* copy out access time */
1701                         shortTemp = dosTime & 0xffff;
1702                         *((u_short *)dptr) = shortTemp;
1703                         dptr += 2;
1704
1705                         /* and copy out date */
1706                         shortTemp = (dosTime>>16) & 0xffff;
1707                         *((u_short *)dptr) = shortTemp;
1708                         dptr += 2;
1709                         
1710                         /* copy out mod time */
1711                         shortTemp = dosTime & 0xffff;
1712                         *((u_short *)dptr) = shortTemp;
1713                         dptr += 2;
1714
1715                         /* copy out file length and alloc length,
1716                          * using the same for both
1717                          */
1718                         *((u_long *)dptr) = scp->length.LowPart;
1719                         dptr += 4;
1720                         *((u_long *)dptr) = scp->length.LowPart;
1721                         dptr += 4;
1722
1723                         /* finally copy out attributes as short */
1724                         attr = smb_Attributes(scp);
1725             /* merge in hidden (dot file) attribute */
1726             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1727                 attr |= SMB_ATTR_HIDDEN;
1728                         *dptr++ = attr & 0xff;
1729                         *dptr++ = (attr >> 8) & 0xff;
1730                 }
1731
1732         lock_ReleaseMutex(&scp->mx);
1733         cm_ReleaseSCache(scp);
1734         }
1735         
1736     /* now free the patches */
1737     for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1738                 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1739         free(patchp);
1740         }
1741         
1742     /* and mark the list as empty */
1743     *dirPatchespp = NULL;
1744
1745     return code;
1746 }
1747
1748 #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) {
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, tidPathp, &req, &scp);
3366         } else
3367             dscp = NULL;
3368     } else {
3369         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3370                         userp, tidPathp, &req, &scp);
3371     }
3372         
3373     if (code == 0) foundscp = TRUE;
3374         if (code != 0
3375             || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3376                 /* look up parent directory */
3377         /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
3378          * the immediate parent.  We have to work our way up realPathp until we hit something that we
3379          * recognize.
3380          */
3381
3382         if ( !dscp ) {
3383         while(1) {
3384             char *tp;
3385
3386             code = cm_NameI(baseDirp, spacep->data,
3387                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3388                              userp, tidPathp, &req, &dscp);
3389
3390             if (code && 
3391                 (tp = strrchr(spacep->data,'\\')) &&
3392                 (createDisp == 2) &&
3393                 (realDirFlag == 1)) {
3394                 *tp++ = 0;
3395                 treeCreate = TRUE;
3396                 treeStartp = realPathp + (tp - spacep->data);
3397
3398                 if (*tp && !smb_IsLegalFilename(tp)) {
3399                     if(baseFid != 0) smb_ReleaseFID(baseFidp);
3400                     cm_ReleaseUser(userp);
3401                     free(realPathp);
3402                     return CM_ERROR_BADNTFILENAME;
3403                 }
3404             }
3405             else
3406                 break;
3407         }
3408         } else
3409             code = 0;
3410
3411         if (baseFid != 0) smb_ReleaseFID(baseFidp);
3412
3413         if (code) {
3414             osi_Log0(smb_logp,"NTCreateX parent not found");
3415             cm_ReleaseUser(userp);
3416             free(realPathp);
3417             return code;
3418         }
3419
3420         if(treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
3421             /* A file exists where we want a directory. */
3422             cm_ReleaseSCache(dscp);
3423             cm_ReleaseUser(userp);
3424             free(realPathp);
3425             return CM_ERROR_EXISTS;
3426         }
3427
3428         if (!lastNamep) lastNamep = realPathp;
3429         else lastNamep++;
3430
3431         if (!smb_IsLegalFilename(lastNamep)) {
3432             cm_ReleaseSCache(dscp);
3433             cm_ReleaseUser(userp);
3434             free(realPathp);
3435             return CM_ERROR_BADNTFILENAME;
3436         }
3437
3438         if (!foundscp && !treeCreate) {
3439             if(createDisp == 2 || createDisp == 4)
3440                 code = cm_Lookup(dscp, lastNamep,
3441                                   CM_FLAG_FOLLOW, userp, &req, &scp);
3442             else
3443                 code = cm_Lookup(dscp, lastNamep,
3444                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3445                                  userp, &req, &scp);
3446                         if (code && code != CM_ERROR_NOSUCHFILE) {
3447                                 cm_ReleaseSCache(dscp);
3448                                 cm_ReleaseUser(userp);
3449                                 free(realPathp);
3450                                 return code;
3451                         }
3452                 }
3453         }
3454         else {
3455                 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3456         }
3457
3458         /* if we get here, if code is 0, the file exists and is represented by
3459          * scp.  Otherwise, we have to create it.  The dir may be represented
3460          * by dscp, or we may have found the file directly.  If code is non-zero,
3461          * scp is NULL.
3462          */
3463         if (code == 0 && !treeCreate) {
3464                 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3465                                       &req);
3466                 if (code) {
3467                         if (dscp) cm_ReleaseSCache(dscp);
3468                         cm_ReleaseSCache(scp);
3469                         cm_ReleaseUser(userp);
3470                         free(realPathp);
3471                         return code;
3472                 }
3473
3474                 if (createDisp == 2) {
3475                         /* oops, file shouldn't be there */
3476                         if (dscp) cm_ReleaseSCache(dscp);
3477                         cm_ReleaseSCache(scp);
3478                         cm_ReleaseUser(userp);
3479                         free(realPathp);
3480                         return CM_ERROR_EXISTS;
3481                 }
3482
3483                 if (createDisp == 4
3484                     || createDisp == 5) {
3485                         setAttr.mask = CM_ATTRMASK_LENGTH;
3486                         setAttr.length.LowPart = 0;
3487                         setAttr.length.HighPart = 0;
3488                         code = cm_SetAttr(scp, &setAttr, userp, &req);
3489                         openAction = 3; /* truncated existing file */
3490                 }
3491                 else openAction = 1;    /* found existing file */
3492         }
3493         else if (createDisp == 1 || createDisp == 4) {
3494                 /* don't create if not found */
3495                 if (dscp) cm_ReleaseSCache(dscp);
3496                 cm_ReleaseUser(userp);
3497                 free(realPathp);
3498                 return CM_ERROR_NOSUCHFILE;
3499         }
3500         else if (realDirFlag == 0 || realDirFlag == -1) {
3501                 osi_assert(dscp != NULL);
3502                 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
3503                                 osi_LogSaveString(smb_logp, lastNamep));
3504                 openAction = 2;         /* created file */
3505                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3506                 setAttr.clientModTime = time(NULL);
3507                 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3508                                  &req);
3509                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3510                         smb_NotifyChange(FILE_ACTION_ADDED,
3511                                          FILE_NOTIFY_CHANGE_FILE_NAME,
3512                                          dscp, lastNamep, NULL, TRUE);
3513                 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3514                         /* Not an exclusive create, and someone else tried
3515                          * creating it already, then we open it anyway.  We
3516                          * don't bother retrying after this, since if this next
3517                          * fails, that means that the file was deleted after we
3518                          * started this call.
3519                          */
3520                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3521                                          userp, &req, &scp);
3522                         if (code == 0) {
3523                                 if (createDisp == 5) {
3524                                         setAttr.mask = CM_ATTRMASK_LENGTH;
3525                                         setAttr.length.LowPart = 0;
3526                                         setAttr.length.HighPart = 0;
3527                                         code = cm_SetAttr(scp, &setAttr, userp,
3528                                                           &req);
3529                                 }
3530                         }       /* lookup succeeded */
3531                 }
3532         }
3533         else {
3534         char *tp, *pp;
3535         char *cp; /* This component */
3536         int clen = 0; /* length of component */
3537         cm_scache_t *tscp;
3538         int isLast = 0;
3539                 
3540         /* create directory */
3541                 if ( !treeCreate ) treeStartp = lastNamep;
3542         osi_assert(dscp != NULL);
3543         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
3544                                 osi_LogSaveString(smb_logp, treeStartp));
3545                 openAction = 2;         /* created directory */
3546
3547                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3548                 setAttr.clientModTime = time(NULL);
3549                 
3550                 pp = treeStartp;
3551                 cp = spacep->data;
3552                 tscp = dscp;
3553
3554                 while(pp && *pp) {
3555                         tp = strchr(pp, '\\');
3556                         if(!tp) {
3557                                 strcpy(cp,pp);
3558                 clen = strlen(cp);
3559                                 isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
3560                         }
3561                         else {
3562                                 clen = tp - pp;
3563                                 strncpy(cp,pp,clen);
3564                                 *(cp + clen) = 0;
3565                                 tp++;
3566                         }
3567                         pp = tp;
3568
3569                         if(clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
3570
3571                         /* cp is the next component to be created. */
3572                         code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
3573                         if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
3574                                 smb_NotifyChange(FILE_ACTION_ADDED,
3575                                 FILE_NOTIFY_CHANGE_DIR_NAME,
3576                                 tscp, cp, NULL, TRUE);
3577                         if (code == 0 || 
3578                                 (code == CM_ERROR_EXISTS && createDisp != 2)) {
3579                                         /* Not an exclusive create, and someone else tried
3580                                         * creating it already, then we open it anyway.  We
3581                                         * don't bother retrying after this, since if this next
3582                                         * fails, that means that the file was deleted after we
3583                                         * started this call.
3584                                         */
3585                                         code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
3586                                                 userp, &req, &scp);
3587                                 }
3588                         if(code) break;
3589
3590                         if(!isLast) { /* for anything other than dscp, release it unless it's the last one */
3591                                 cm_ReleaseSCache(tscp);
3592                                 tscp = scp; /* Newly created directory will be next parent */
3593                         }
3594                 }
3595
3596                 /* 
3597                 if we get here and code == 0, then scp is the last directory created, and tscp is the
3598                 parent of scp.  dscp got released if dscp != tscp. both tscp and scp are held.
3599                 */
3600                 dscp = tscp;
3601         }
3602
3603         if (code) {
3604                 /* something went wrong creating or truncating the file */
3605                 if (scp) cm_ReleaseSCache(scp);
3606         if (dscp) cm_ReleaseSCache(dscp);
3607                 cm_ReleaseUser(userp);
3608                 free(realPathp);
3609                 return code;
3610         }
3611
3612         /* make sure we have file vs. dir right (only applies for single component case) */
3613         if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3614                 cm_ReleaseSCache(scp);
3615         if (dscp) cm_ReleaseSCache(dscp);
3616                 cm_ReleaseUser(userp);
3617                 free(realPathp);
3618                 return CM_ERROR_ISDIR;
3619         }
3620     /* (only applies to single component case) */
3621         if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3622                 cm_ReleaseSCache(scp);
3623         if (dscp) cm_ReleaseSCache(dscp);
3624                 cm_ReleaseUser(userp);
3625                 free(realPathp);
3626                 return CM_ERROR_NOTDIR;
3627         }
3628
3629         /* open the file itself */
3630         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3631         osi_assert(fidp);
3632         /* save a pointer to the vnode */
3633         fidp->scp = scp;
3634
3635         fidp->flags = fidflags;
3636
3637         /* save parent dir and pathname for delete or change notification */
3638         if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3639                 fidp->flags |= SMB_FID_NTOPEN;
3640                 fidp->NTopen_dscp = dscp;
3641                 cm_HoldSCache(dscp);
3642                 fidp->NTopen_pathp = strdup(lastNamep);
3643         }
3644         fidp->NTopen_wholepathp = realPathp;
3645
3646         /* we don't need this any longer */
3647         if (dscp) cm_ReleaseSCache(dscp);
3648         cm_Open(scp, 0, userp);
3649
3650         /* set inp->fid so that later read calls in same msg can find fid */
3651         inp->fid = fidp->fid;
3652
3653         /* out parms */
3654         parmSlot = 2;
3655         lock_ObtainMutex(&scp->mx);
3656         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
3657         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3658         smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3659         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3660         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3661         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3662         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3663         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3664         smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3665                                                 parmSlot += 2;
3666         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3667         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3668         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
3669         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
3670         smb_SetSMBParmByte(outp, parmSlot,
3671                 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3672         lock_ReleaseMutex(&scp->mx);
3673         smb_SetSMBDataLength(outp, 0);
3674
3675         osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3676                  osi_LogSaveString(smb_logp, realPathp));
3677
3678         smb_ReleaseFID(fidp);
3679
3680         cm_ReleaseUser(userp);
3681
3682     /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
3683
3684         /* leave scp held since we put it in fidp->scp */
3685         return 0;
3686 }
3687
3688 /*
3689  * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3690  * Instead, ultimately, would like to use a subroutine for common code.
3691  */
3692 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3693 {
3694         char *pathp, *realPathp;
3695         long code = 0;
3696         cm_space_t *spacep;
3697         cm_user_t *userp;
3698         cm_scache_t *dscp;              /* parent dir */
3699         cm_scache_t *scp;               /* file to create or open */
3700         cm_attr_t setAttr;
3701         char *lastNamep;
3702         unsigned long nameLength;
3703         unsigned int flags;
3704         unsigned int requestOpLock;
3705         unsigned int requestBatchOpLock;
3706         unsigned int mustBeDir;
3707     unsigned int extendedRespRequired;
3708         int realDirFlag;
3709         unsigned int desiredAccess;
3710 #ifdef DEBUG_VERBOSE    
3711     unsigned int allocSize;
3712     unsigned int shareAccess;
3713 #endif
3714         unsigned int extAttributes;
3715         unsigned int createDisp;
3716 #ifdef DEBUG_VERBOSE
3717     unsigned int sdLen;
3718 #endif
3719         unsigned int createOptions;
3720         int initialModeBits;
3721         unsigned short baseFid;
3722         smb_fid_t *baseFidp;
3723         smb_fid_t *fidp;
3724         cm_scache_t *baseDirp;
3725         unsigned short openAction;
3726         int parmSlot;
3727         long fidflags;
3728         FILETIME ft;
3729         char *tidPathp;
3730         BOOL foundscp;
3731         int parmOffset, dataOffset;
3732         char *parmp;
3733         ULONG *lparmp;
3734         char *outData;
3735         cm_req_t req;
3736
3737         cm_InitReq(&req);
3738
3739         foundscp = FALSE;
3740         scp = NULL;
3741
3742         parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3743                         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3744         parmp = inp->data + parmOffset;
3745         lparmp = (ULONG *) parmp;
3746
3747         flags = lparmp[0];
3748         requestOpLock = flags & 0x02;
3749         requestBatchOpLock = flags & 0x04;
3750         mustBeDir = flags & 0x08;
3751     extendedRespRequired = flags & 0x10;
3752
3753         /*
3754          * Why all of a sudden 32-bit FID?
3755          * We will reject all bits higher than 16.
3756          */
3757         if (lparmp[1] & 0xFFFF0000)
3758                 return CM_ERROR_INVAL;
3759         baseFid = (unsigned short)lparmp[1];
3760         desiredAccess = lparmp[2];
3761 #ifdef DEBUG_VERBOSE
3762     allocSize = lparmp[3];
3763 #endif /* DEBUG_VERSOSE */
3764         extAttributes = lparmp[5];
3765 #ifdef DEBUG_VEROSE
3766     shareAccess = lparmp[6];
3767 #endif
3768         createDisp = lparmp[7];
3769         createOptions = lparmp[8];
3770 #ifdef DEBUG_VERBOSE
3771     sdLen = lparmp[9];
3772 #endif
3773         nameLength = lparmp[11];
3774
3775 #ifdef DEBUG_VERBOSE
3776         osi_Log4(smb_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
3777         osi_Log2(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
3778         osi_Log1(smb_logp,"... flags[%x]",flags);
3779 #endif
3780
3781         /* mustBeDir is never set; createOptions directory bit seems to be
3782          * more important
3783          */
3784         if (createOptions & 1)
3785                 realDirFlag = 1;
3786         else if (createOptions & 0x40)
3787                 realDirFlag = 0;
3788         else
3789                 realDirFlag = -1;
3790
3791         /*
3792          * compute initial mode bits based on read-only flag in
3793          * extended attributes
3794          */
3795         initialModeBits = 0666;
3796         if (extAttributes & 1) initialModeBits &= ~0222;
3797
3798         pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3799         /* Sometimes path is not null-terminated, so we make a copy. */
3800         realPathp = malloc(nameLength+1);
3801         memcpy(realPathp, pathp, nameLength);
3802         realPathp[nameLength] = 0;
3803
3804         spacep = cm_GetSpace();
3805         smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3806
3807         /*
3808          * Nothing here to handle SMB_IOCTL_FILENAME.
3809          * Will add it if necessary.
3810          */
3811
3812 #ifdef DEBUG_VERBOSE
3813         {
3814                 char *hexp, *asciip;
3815                 asciip = (lastNamep? lastNamep : realPathp);
3816                 hexp = osi_HexifyString( asciip );
3817                 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
3818                 free(hexp);
3819         }
3820 #endif
3821
3822         userp = smb_GetUser(vcp, inp);
3823     if(!userp) {
3824         osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
3825         free(realPathp);
3826         return CM_ERROR_INVAL;
3827     }
3828
3829         if (baseFid == 0) {
3830                 baseDirp = cm_rootSCachep;
3831                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3832         }
3833         else {
3834         baseFidp = smb_FindFID(vcp, baseFid, 0);
3835         if(!baseFidp) {
3836                 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
3837                 free(realPathp);
3838                 cm_ReleaseUser(userp);
3839                 return CM_ERROR_INVAL;
3840         }
3841                 baseDirp = baseFidp->scp;
3842                 tidPathp = NULL;
3843         }
3844
3845     /* compute open mode */
3846     fidflags = 0;
3847     if (desiredAccess & DELETE)
3848         fidflags |= SMB_FID_OPENDELETE;
3849     if (desiredAccess & AFS_ACCESS_READ)
3850         fidflags |= SMB_FID_OPENREAD;
3851     if (desiredAccess & AFS_ACCESS_WRITE)
3852         fidflags |= SMB_FID_OPENWRITE;
3853
3854         dscp = NULL;
3855         code = 0;
3856     if (createDisp == 2 || createDisp == 4) {
3857         code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3858                         userp, tidPathp, &req, &dscp);
3859         if (code == 0) {
3860             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
3861                              userp, tidPathp, &req, &scp);
3862         } else 
3863             dscp = NULL;
3864     } else {
3865         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3866                         userp, tidPathp, &req, &scp);
3867     }
3868
3869         if (code == 0) foundscp = TRUE;
3870         if (code != 0
3871             || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3872                 /* look up parent directory */
3873         if ( !dscp ) {
3874             code = cm_NameI(baseDirp, spacep->data,
3875                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3876                              userp, tidPathp, &req, &dscp);
3877         } else
3878             code = 0;
3879         
3880         cm_FreeSpace(spacep);
3881
3882                 if (baseFid != 0) {
3883            smb_ReleaseFID(baseFidp);
3884            baseFidp = 0;
3885         }
3886
3887                 if (code) {
3888                         cm_ReleaseUser(userp);
3889                         free(realPathp);
3890                         return code;
3891                 }
3892
3893                 if (!lastNamep) lastNamep = realPathp;
3894                 else lastNamep++;
3895
3896         if (!smb_IsLegalFilename(lastNamep))
3897             return CM_ERROR_BADNTFILENAME;
3898
3899                 if (!foundscp) {
3900             if (createDisp == 2 || createDisp == 4)
3901                 code = cm_Lookup(dscp, lastNamep,
3902                                  CM_FLAG_FOLLOW, userp, &req, &scp);
3903             else
3904                 code = cm_Lookup(dscp, lastNamep,
3905                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3906                                  userp, &req, &scp);
3907                         if (code && code != CM_ERROR_NOSUCHFILE) {
3908                                 cm_ReleaseSCache(dscp);
3909                                 cm_ReleaseUser(userp);
3910                                 free(realPathp);
3911                                 return code;
3912                         }
3913                 }
3914         }
3915         else {
3916                 if (baseFid != 0) {
3917             smb_ReleaseFID(baseFidp);
3918             baseFidp = 0;
3919         }
3920                 cm_FreeSpace(spacep);
3921         }
3922
3923         /* if we get here, if code is 0, the file exists and is represented by
3924          * scp.  Otherwise, we have to create it.  The dir may be represented
3925          * by dscp, or we may have found the file directly.  If code is non-zero,
3926          * scp is NULL.
3927          */
3928         if (code == 0) {
3929                 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3930                                       &req);
3931                 if (code) {
3932                         if (dscp) cm_ReleaseSCache(dscp);
3933                         cm_ReleaseSCache(scp);
3934                         cm_ReleaseUser(userp);
3935                         free(realPathp);
3936                         return code;
3937                 }
3938
3939                 if (createDisp == 2) {
3940                         /* oops, file shouldn't be there */
3941                         if (dscp) cm_ReleaseSCache(dscp);
3942                         cm_ReleaseSCache(scp);
3943                         cm_ReleaseUser(userp);
3944                         free(realPathp);
3945                         return CM_ERROR_EXISTS;
3946                 }
3947
3948                 if (createDisp == 4
3949                     || createDisp == 5) {
3950                         setAttr.mask = CM_ATTRMASK_LENGTH;
3951                         setAttr.length.LowPart = 0;
3952                         setAttr.length.HighPart = 0;
3953                         code = cm_SetAttr(scp, &setAttr, userp, &req);
3954                         openAction = 3; /* truncated existing file */
3955                 }
3956                 else openAction = 1;    /* found existing file */
3957         }
3958         else if (createDisp == 1 || createDisp == 4) {
3959                 /* don't create if not found */
3960                 if (dscp) cm_ReleaseSCache(dscp);
3961                 cm_ReleaseUser(userp);
3962                 free(realPathp);
3963                 return CM_ERROR_NOSUCHFILE;
3964         }
3965         else if (realDirFlag == 0 || realDirFlag == -1) {
3966                 osi_assert(dscp != NULL);
3967                 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
3968                  osi_LogSaveString(smb_logp, lastNamep));
3969                 openAction = 2;         /* created file */
3970                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3971                 setAttr.clientModTime = time(NULL);
3972                 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3973                                  &req);
3974                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3975                         smb_NotifyChange(FILE_ACTION_ADDED,
3976                                          FILE_NOTIFY_CHANGE_FILE_NAME,
3977                                          dscp, lastNamep, NULL, TRUE);
3978                 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3979                         /* Not an exclusive create, and someone else tried
3980                          * creating it already, then we open it anyway.  We
3981                          * don't bother retrying after this, since if this next
3982                          * fails, that means that the file was deleted after we
3983                          * started this call.
3984                          */
3985                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3986                                          userp, &req, &scp);
3987                         if (code == 0) {
3988                                 if (createDisp == 5) {
3989                                         setAttr.mask = CM_ATTRMASK_LENGTH;
3990                                         setAttr.length.LowPart = 0;
3991                                         setAttr.length.HighPart = 0;
3992                                         code = cm_SetAttr(scp, &setAttr, userp,
3993                                                           &req);
3994                                 }
3995                         }       /* lookup succeeded */
3996                 }
3997         }
3998         else {
3999                 /* create directory */
4000                 osi_assert(dscp != NULL);
4001                 osi_Log1(smb_logp,
4002                                 "smb_ReceiveNTTranCreate creating directory %s",
4003                                 osi_LogSaveString(smb_logp, lastNamep));
4004                 openAction = 2;         /* created directory */
4005                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4006                 setAttr.clientModTime = time(NULL);
4007                 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
4008                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4009                         smb_NotifyChange(FILE_ACTION_ADDED,
4010                                          FILE_NOTIFY_CHANGE_DIR_NAME,
4011                                          dscp, lastNamep, NULL, TRUE);
4012                 if (code == 0
4013                     || (code == CM_ERROR_EXISTS && createDisp != 2)) {
4014                         /* Not an exclusive create, and someone else tried
4015                          * creating it already, then we open it anyway.  We
4016                          * don't bother retrying after this, since if this next
4017                          * fails, that means that the file was deleted after we
4018                          * started this call.
4019                          */
4020                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4021                                          userp, &req, &scp);
4022                 }
4023         }
4024
4025         if (code) {
4026                 /* something went wrong creating or truncating the file */
4027                 if (scp) cm_ReleaseSCache(scp);
4028                 cm_ReleaseUser(userp);
4029                 free(realPathp);
4030                 return code;
4031         }
4032
4033         /* make sure we have file vs. dir right */
4034         if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
4035                 cm_ReleaseSCache(scp);
4036                 cm_ReleaseUser(userp);
4037                 free(realPathp);
4038                 return CM_ERROR_ISDIR;
4039         }
4040         if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
4041                 cm_ReleaseSCache(scp);
4042                 cm_ReleaseUser(userp);
4043                 free(realPathp);
4044                 return CM_ERROR_NOTDIR;
4045         }
4046
4047         /* open the file itself */
4048         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4049         osi_assert(fidp);
4050
4051         /* save a pointer to the vnode */
4052         fidp->scp = scp;
4053
4054         fidp->flags = fidflags;
4055
4056     /* save parent dir and pathname for deletion or change notification */
4057     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
4058         fidp->flags |= SMB_FID_NTOPEN;
4059         fidp->NTopen_dscp = dscp;
4060         cm_HoldSCache(dscp);
4061         fidp->NTopen_pathp = strdup(lastNamep);
4062     }
4063         fidp->NTopen_wholepathp = realPathp;
4064
4065         /* we don't need this any longer */
4066         if (dscp) cm_ReleaseSCache(dscp);
4067
4068         cm_Open(scp, 0, userp);
4069
4070         /* set inp->fid so that later read calls in same msg can find fid */
4071         inp->fid = fidp->fid;
4072
4073     /* check whether we are required to send an extended response */
4074     if (!extendedRespRequired) {
4075         /* out parms */
4076         parmOffset = 8*4 + 39;
4077         parmOffset += 1;        /* pad to 4 */
4078         dataOffset = parmOffset + 70;
4079
4080         parmSlot = 1;
4081         outp->oddByte = 1;
4082         /* Total Parameter Count */
4083         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
4084         /* Total Data Count */
4085         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4086         /* Parameter Count */
4087         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
4088         /* Parameter Offset */
4089         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4090         /* Parameter Displacement */
4091         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4092         /* Data Count */
4093         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4094         /* Data Offset */
4095         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4096         /* Data Displacement */
4097         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4098         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
4099         smb_SetSMBDataLength(outp, 70);
4100
4101         lock_ObtainMutex(&scp->mx);
4102         outData = smb_GetSMBData(outp, NULL);
4103         outData++;                      /* round to get to parmOffset */
4104         *outData = 0; outData++;        /* oplock */
4105         *outData = 0; outData++;        /* reserved */
4106         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
4107         *((ULONG *)outData) = openAction; outData += 4;
4108         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
4109         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4110         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
4111         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
4112         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
4113         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
4114         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
4115         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
4116         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
4117         *((USHORT *)outData) = 0; outData += 2; /* filetype */
4118         *((USHORT *)outData) = 0; outData += 2; /* dev state */
4119         *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
4120         outData += 2;   /* is a dir? */
4121         lock_ReleaseMutex(&scp->mx);
4122     } else {
4123         /* out parms */
4124         parmOffset = 8*4 + 39;
4125         parmOffset += 1;        /* pad to 4 */
4126         dataOffset = parmOffset + 104;
4127         
4128         parmSlot = 1;
4129         outp->oddByte = 1;
4130         /* Total Parameter Count */
4131         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
4132         /* Total Data Count */
4133         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4134         /* Parameter Count */
4135         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
4136         /* Parameter Offset */
4137         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4138         /* Parameter Displacement */
4139         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4140         /* Data Count */
4141         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4142         /* Data Offset */
4143         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4144         /* Data Displacement */
4145         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4146         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
4147         smb_SetSMBDataLength(outp, 105);
4148         
4149         lock_ObtainMutex(&scp->mx);
4150         outData = smb_GetSMBData(outp, NULL);
4151         outData++;                      /* round to get to parmOffset */
4152         *outData = 0; outData++;        /* oplock */
4153         *outData = 1; outData++;        /* response type */
4154         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
4155         *((ULONG *)outData) = openAction; outData += 4;
4156         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
4157         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4158         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
4159         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
4160         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
4161         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
4162         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
4163         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
4164         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
4165         *((USHORT *)outData) = 0; outData += 2; /* filetype */
4166         *((USHORT *)outData) = 0; outData += 2; /* dev state */
4167         *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
4168         outData += 1;   /* is a dir? */
4169         memset(outData,0,24); outData += 24; /* Volume ID and file ID */
4170         *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
4171         *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
4172         lock_ReleaseMutex(&scp->mx);
4173     }
4174
4175         osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
4176
4177         smb_ReleaseFID(fidp);
4178
4179         cm_ReleaseUser(userp);
4180
4181         /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
4182         /* leave scp held since we put it in fidp->scp */
4183         return 0;
4184 }
4185
4186 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
4187         smb_packet_t *outp)
4188 {
4189         smb_packet_t *savedPacketp;
4190         ULONG filter; USHORT fid, watchtree;
4191         smb_fid_t *fidp;
4192         cm_scache_t *scp;
4193         
4194         filter = smb_GetSMBParm(inp, 19)
4195                         | (smb_GetSMBParm(inp, 20) << 16);
4196         fid = smb_GetSMBParm(inp, 21);
4197         watchtree = smb_GetSMBParm(inp, 22) && 0xffff;  /* TODO: should this be 0xff ? */
4198
4199     fidp = smb_FindFID(vcp, fid, 0);
4200     if (!fidp) {
4201         osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
4202         return CM_ERROR_BADFD;
4203     }
4204
4205         savedPacketp = smb_CopyPacket(inp);
4206         savedPacketp->vcp = vcp; /* TODO: refcount vcp? */
4207         lock_ObtainMutex(&smb_Dir_Watch_Lock);
4208         savedPacketp->nextp = smb_Directory_Watches;
4209         smb_Directory_Watches = savedPacketp;
4210         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4211
4212     osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
4213              filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
4214
4215     scp = fidp->scp;
4216     lock_ObtainMutex(&scp->mx);
4217     if (watchtree)
4218         scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
4219     else
4220         scp->flags |= CM_SCACHEFLAG_WATCHED;
4221     lock_ReleaseMutex(&scp->mx);
4222     smb_ReleaseFID(fidp);
4223
4224         outp->flags |= SMB_PACKETFLAG_NOSEND;
4225         return 0;
4226 }
4227
4228 unsigned char nullSecurityDesc[36] = {
4229         0x01,                           /* security descriptor revision */
4230         0x00,                           /* reserved, should be zero */
4231         0x00, 0x80,                     /* security descriptor control;
4232                                          * 0x8000 : self-relative format */
4233         0x14, 0x00, 0x00, 0x00,         /* offset of owner SID */
4234         0x1c, 0x00, 0x00, 0x00,         /* offset of group SID */
4235         0x00, 0x00, 0x00, 0x00,         /* offset of DACL would go here */
4236         0x00, 0x00, 0x00, 0x00,         /* offset of SACL would go here */
4237         0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4238                                         /* "null SID" owner SID */
4239         0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4240                                         /* "null SID" group SID */
4241 };
4242
4243 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4244 {
4245         int parmOffset, parmCount, dataOffset, dataCount;
4246         int parmSlot;
4247         int maxData;
4248         char *outData;
4249         char *parmp;
4250         USHORT *sparmp;
4251         ULONG *lparmp;
4252         USHORT fid;
4253         ULONG securityInformation;
4254
4255         parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
4256                         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
4257         parmp = inp->data + parmOffset;
4258         sparmp = (USHORT *) parmp;
4259         lparmp = (ULONG *) parmp;
4260
4261         fid = sparmp[0];
4262         securityInformation = lparmp[1];
4263
4264         maxData = smb_GetSMBOffsetParm(inp, 7, 1)
4265                         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4266
4267         if (maxData < 36)
4268                 dataCount = 0;
4269         else
4270                 dataCount = 36;
4271
4272         /* out parms */
4273         parmOffset = 8*4 + 39;
4274         parmOffset += 1;        /* pad to 4 */
4275         parmCount = 4;
4276         dataOffset = parmOffset + parmCount;
4277
4278         parmSlot = 1;
4279         outp->oddByte = 1;
4280         /* Total Parameter Count */
4281         smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
4282         /* Total Data Count */
4283         smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
4284         /* Parameter Count */
4285         smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
4286         /* Parameter Offset */
4287         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4288         /* Parameter Displacement */
4289         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4290         /* Data Count */
4291         smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
4292         /* Data Offset */
4293         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4294         /* Data Displacement */
4295         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4296         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
4297         smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
4298
4299         outData = smb_GetSMBData(outp, NULL);
4300         outData++;                      /* round to get to parmOffset */
4301         *((ULONG *)outData) = 36; outData += 4; /* length */
4302
4303         if (maxData >= 36) {
4304                 memcpy(outData, nullSecurityDesc, 36);
4305                 outData += 36;
4306                 return 0;
4307         } else
4308                 return CM_ERROR_BUFFERTOOSMALL;
4309 }
4310
4311 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4312 {
4313         unsigned short function;
4314
4315         function = smb_GetSMBParm(inp, 18);
4316
4317         osi_Log1(smb_logp, "SMB NT Transact function %d", function);
4318
4319         /* We can handle long names */
4320         if (vcp->flags & SMB_VCFLAG_USENT)
4321                 ((smb_t *)outp)->flg2 |= 0x40;  /* IS_LONG_NAME */
4322         
4323         switch (function) {
4324
4325                 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
4326
4327                 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
4328
4329                 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
4330
4331                 default: return CM_ERROR_INVAL;
4332         }
4333 }
4334
4335 /*
4336  * smb_NotifyChange -- find relevant change notification messages and
4337  *                     reply to them
4338  *
4339  * If we don't know the file name (i.e. a callback break), filename is
4340  * NULL, and we return a zero-length list.
4341  */
4342 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
4343         cm_scache_t *dscp, char *filename, char *otherFilename,
4344         BOOL isDirectParent)
4345 {
4346         smb_packet_t *watch, *lastWatch, *nextWatch;
4347         ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
4348         char *outData, *oldOutData;
4349         ULONG filter;
4350         USHORT fid, wtree;
4351         ULONG maxLen;
4352         BOOL twoEntries = FALSE;
4353         ULONG otherNameLen, oldParmCount = 0;
4354         DWORD otherAction;
4355         smb_vc_t *vcp;
4356         smb_fid_t *fidp;
4357
4358         /* Get ready for rename within directory */
4359         if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
4360                 twoEntries = TRUE;
4361                 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
4362         }
4363
4364         lock_ObtainMutex(&smb_Dir_Watch_Lock);
4365         watch = smb_Directory_Watches;
4366         while (watch) {
4367                 filter = smb_GetSMBParm(watch, 19)
4368                                 | (smb_GetSMBParm(watch, 20) << 16);
4369                 fid = smb_GetSMBParm(watch, 21);
4370                 wtree = smb_GetSMBParm(watch, 22) & 0xffff;  /* TODO: should this be 0xff ? */
4371                 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
4372                                 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
4373                 vcp = watch->vcp;
4374
4375                 /*
4376                  * Strange hack - bug in NT Client and NT Server that we
4377                  * must emulate?
4378                  */
4379                 if (filter == 3 && wtree)
4380                         filter = 0x17;
4381
4382                 fidp = smb_FindFID(vcp, fid, 0);
4383         if (!fidp) {
4384                 lastWatch = watch;
4385                 watch = watch->nextp;
4386                 continue;
4387         }
4388                 if (fidp->scp != dscp
4389                     || (filter & notifyFilter) == 0
4390                     || (!isDirectParent && !wtree)) {
4391                         smb_ReleaseFID(fidp);
4392                         lastWatch = watch;
4393                         watch = watch->nextp;
4394                         continue;
4395                 }
4396                 smb_ReleaseFID(fidp);
4397
4398                 osi_Log4(smb_logp,
4399                          "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
4400                          fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
4401
4402                 nextWatch = watch->nextp;
4403                 if (watch == smb_Directory_Watches)
4404                         smb_Directory_Watches = nextWatch;
4405                 else
4406                         lastWatch->nextp = nextWatch;
4407
4408                 /* Turn off WATCHED flag in dscp */
4409                 lock_ObtainMutex(&dscp->mx);
4410                 if (wtree)
4411                         dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4412                 else
4413                         dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
4414                 lock_ReleaseMutex(&dscp->mx);
4415
4416                 /* Convert to response packet */
4417                 ((smb_t *) watch)->reb = 0x80;
4418                 ((smb_t *) watch)->wct = 0;
4419
4420                 /* out parms */
4421                 if (filename == NULL)
4422                         parmCount = 0;
4423                 else {
4424                         nameLen = strlen(filename);
4425                         parmCount = 3*4 + nameLen*2;
4426                         parmCount = (parmCount + 3) & ~3;       /* pad to 4 */
4427                         if (twoEntries) {
4428                                 otherNameLen = strlen(otherFilename);
4429                                 oldParmCount = parmCount;
4430                                 parmCount += 3*4 + otherNameLen*2;
4431                                 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
4432                         }
4433                         if (maxLen < parmCount)
4434                                 parmCount = 0;  /* not enough room */
4435                 }
4436                 parmOffset = 8*4 + 39;
4437                 parmOffset += 1;                        /* pad to 4 */
4438                 dataOffset = parmOffset + parmCount;
4439
4440                 parmSlot = 1;
4441                 watch->oddByte = 1;
4442                 /* Total Parameter Count */
4443                 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4444                 /* Total Data Count */
4445                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4446                 /* Parameter Count */
4447                 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4448                 /* Parameter Offset */
4449                 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
4450                 /* Parameter Displacement */
4451                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4452                 /* Data Count */
4453                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4454                 /* Data Offset */
4455                 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
4456                 /* Data Displacement */
4457                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4458                 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
4459                 smb_SetSMBDataLength(watch, parmCount + 1);
4460
4461                 if (parmCount != 0) {
4462                         outData = smb_GetSMBData(watch, NULL);
4463                         outData++;      /* round to get to parmOffset */
4464                         oldOutData = outData;
4465                         *((DWORD *)outData) = oldParmCount; outData += 4;
4466                                         /* Next Entry Offset */
4467                         *((DWORD *)outData) = action; outData += 4;
4468                                         /* Action */
4469                         *((DWORD *)outData) = nameLen*2; outData += 4;
4470                                         /* File Name Length */
4471                         mbstowcs((WCHAR *)outData, filename, nameLen);
4472                                         /* File Name */
4473                         if (twoEntries) {
4474                                 outData = oldOutData + oldParmCount;
4475                                 *((DWORD *)outData) = 0; outData += 4;
4476                                         /* Next Entry Offset */
4477                                 *((DWORD *)outData) = otherAction; outData += 4;
4478                                         /* Action */
4479                                 *((DWORD *)outData) = otherNameLen*2;
4480                                 outData += 4;   /* File Name Length */
4481                                 mbstowcs((WCHAR *)outData, otherFilename,
4482                                          otherNameLen); /* File Name */
4483                         }
4484                 }
4485
4486                 /*
4487                  * If filename is null, we don't know the cause of the
4488                  * change notification.  We return zero data (see above),
4489                  * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
4490                  * (= 0x010C).  We set the error code here by hand, without
4491                  * modifying wct and bcc.
4492                  */
4493                 if (filename == NULL) {
4494                         ((smb_t *) watch)->rcls = 0x0C;
4495                         ((smb_t *) watch)->reh = 0x01;
4496                         ((smb_t *) watch)->errLow = 0;
4497                         ((smb_t *) watch)->errHigh = 0;
4498                         /* Set NT Status codes flag */
4499                         ((smb_t *) watch)->flg2 |= 0x4000;
4500                 }
4501
4502                 smb_SendPacket(vcp, watch);
4503                 smb_FreePacket(watch);
4504                 watch = nextWatch;
4505         }
4506         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4507 }
4508
4509 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4510 {
4511         unsigned char *replyWctp;
4512         smb_packet_t *watch, *lastWatch;
4513         USHORT fid, watchtree;
4514         smb_fid_t *fidp;
4515         cm_scache_t *scp;
4516
4517         osi_Log0(smb_logp, "SMB3 receive NT cancel");
4518
4519         lock_ObtainMutex(&smb_Dir_Watch_Lock);
4520         watch = smb_Directory_Watches;
4521         while (watch) {
4522                 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
4523                     && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
4524                     && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
4525                     && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
4526                         if (watch == smb_Directory_Watches)
4527                                 smb_Directory_Watches = watch->nextp;
4528                         else
4529                                 lastWatch->nextp = watch->nextp;
4530                         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4531
4532                         /* Turn off WATCHED flag in scp */
4533                         fid = smb_GetSMBParm(watch, 21);
4534                         watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
4535
4536                         fidp = smb_FindFID(vcp, fid, 0);
4537             if (fidp) {
4538                 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s", 
4539                          fid, watchtree,
4540                          osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
4541
4542                 scp = fidp->scp;
4543                 lock_ObtainMutex(&scp->mx);
4544                 if (watchtree)
4545                     scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4546                 else
4547                     scp->flags &= ~CM_SCACHEFLAG_WATCHED;
4548                 lock_ReleaseMutex(&scp->mx);
4549                 smb_ReleaseFID(fidp);
4550             } else {
4551                 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
4552             }
4553
4554                         /* assume STATUS32; return 0xC0000120 (CANCELED) */
4555                         replyWctp = watch->wctp;
4556                         *replyWctp++ = 0;
4557                         *replyWctp++ = 0;
4558                         *replyWctp++ = 0;
4559                         ((smb_t *)watch)->rcls = 0x20;
4560                         ((smb_t *)watch)->reh = 0x1;
4561                         ((smb_t *)watch)->errLow = 0;
4562                         ((smb_t *)watch)->errHigh = 0xC0;
4563                         ((smb_t *)watch)->flg2 |= 0x4000;
4564                         smb_SendPacket(vcp, watch);
4565                         smb_FreePacket(watch);
4566                         return 0;
4567                 }
4568                 lastWatch = watch;
4569                 watch = watch->nextp;
4570         }
4571         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4572
4573         return 0;
4574 }
4575
4576 void smb3_Init()
4577 {
4578         lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
4579 }
4580
4581 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
4582 {
4583     /*int newUid;*/
4584     smb_username_t *unp;
4585
4586     unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
4587     if (!unp->userp) {
4588         lock_ObtainMutex(&unp->mx);
4589         unp->userp = cm_NewUser();
4590         lock_ReleaseMutex(&unp->mx);
4591                 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
4592     }  else     {
4593                 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);
4594         }
4595     return unp->userp;
4596 }
4597