44acc8dd471f6898df6d275ea7e9be1cc38a7af2
[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 (stricmp(dep->name, rockp->maskp) != 0)
1057                 return 0;
1058         if (ntohl(dep->fid.vnode) != rockp->vnode)
1059                 return 0;
1060         /* This is the entry */
1061         cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1062         rockp->shortNameLen = shortNameEnd - rockp->shortName;
1063         return CM_ERROR_STOPNOW;
1064 }
1065
1066 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1067         char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1068 {
1069         struct smb_ShortNameRock rock;
1070         char *lastNamep;
1071         cm_space_t *spacep;
1072         cm_scache_t *dscp;
1073         int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1074         long code = 0;
1075         osi_hyper_t thyper;
1076
1077         spacep = cm_GetSpace();
1078         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1079
1080         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1081                      reqp, &dscp);
1082         cm_FreeSpace(spacep);
1083         if (code) return code;
1084
1085         if (!lastNamep) lastNamep = pathp;
1086         else lastNamep++;
1087         thyper.LowPart = 0;
1088         thyper.HighPart = 0;
1089         rock.shortName = shortName;
1090         rock.vnode = vnode;
1091         rock.maskp = lastNamep;
1092         code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1093                         reqp, NULL);
1094
1095         cm_ReleaseSCache(dscp);
1096
1097         if (code == 0)
1098                 return CM_ERROR_NOSUCHFILE;
1099         if (code == CM_ERROR_STOPNOW) {
1100                 *shortNameLenp = rock.shortNameLen;
1101                 return 0;
1102         }
1103         return code;
1104 }
1105
1106 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1107 {
1108         smb_tran2Packet_t *outp;
1109     unsigned long dosTime;
1110         FILETIME ft;
1111     unsigned short infoLevel;
1112     int nbytesRequired;
1113     unsigned short attributes;
1114         unsigned long extAttributes;
1115         char shortName[13];
1116         unsigned int len;
1117     cm_user_t *userp;
1118         cm_space_t *spacep;
1119     cm_scache_t *scp, *dscp;
1120     long code = 0;
1121     char *op;
1122         char *tidPathp;
1123         char *lastComp;
1124         cm_req_t req;
1125
1126         cm_InitReq(&req);
1127
1128         infoLevel = p->parmsp[0];
1129     if (infoLevel == 6) nbytesRequired = 0;
1130     else if (infoLevel == 1) nbytesRequired = 22;
1131     else if (infoLevel == 2) nbytesRequired = 26;
1132         else if (infoLevel == 0x101) nbytesRequired = 40;
1133         else if (infoLevel == 0x102) nbytesRequired = 24;
1134         else if (infoLevel == 0x103) nbytesRequired = 4;
1135         else if (infoLevel == 0x108) nbytesRequired = 30;
1136     else {
1137                 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1138                   p->opcode, infoLevel);
1139                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1140         return 0;
1141     }
1142         osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1143              osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
1144
1145     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1146
1147         if (infoLevel > 0x100)
1148                 outp->totalParms = 2;
1149         else
1150                 outp->totalParms = 0;
1151         outp->totalData = nbytesRequired;
1152         
1153     /* now, if we're at infoLevel 6, we're only being asked to check
1154      * the syntax, so we just OK things now.  In particular, we're *not*
1155      * being asked to verify anything about the state of any parent dirs.
1156      */
1157         if (infoLevel == 6) {
1158                 smb_SendTran2Packet(vcp, outp, opx);
1159         smb_FreeTran2Packet(outp);
1160                 return 0;
1161     }
1162         
1163     userp = smb_GetTran2User(vcp, p);
1164     if(!userp) {
1165         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
1166         smb_FreeTran2Packet(outp);
1167         return CM_ERROR_BADSMB;
1168     }
1169
1170         tidPathp = smb_GetTIDPath(vcp, p->tid);
1171
1172         /*
1173          * XXX Strange hack XXX
1174          *
1175          * As of Patch 7 (13 January 98), we are having the following problem:
1176          * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1177          * requests to look up "desktop.ini" in all the subdirectories.
1178          * This can cause zillions of timeouts looking up non-existent cells
1179          * and volumes, especially in the top-level directory.
1180          *
1181          * We have not found any way to avoid this or work around it except
1182          * to explicitly ignore the requests for mount points that haven't
1183          * yet been evaluated and for directories that haven't yet been
1184          * fetched.
1185          */
1186         if (infoLevel == 0x101) {
1187                 spacep = cm_GetSpace();
1188                 smb_StripLastComponent(spacep->data, &lastComp,
1189                                         (char *)(&p->parmsp[3]));
1190                 /* Make sure that lastComp is not NULL */
1191                 if (lastComp) {
1192                     if (strcmp(lastComp, "\\desktop.ini") == 0) {
1193                 code = cm_NameI(cm_rootSCachep, spacep->data,
1194                                 CM_FLAG_CASEFOLD
1195                                 | CM_FLAG_DIRSEARCH
1196                                 | CM_FLAG_FOLLOW,
1197                                 userp, tidPathp, &req, &dscp);
1198                 if (code == 0) {
1199                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1200                          && !dscp->mountRootFidp)
1201                         code = CM_ERROR_NOSUCHFILE;
1202                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1203                         cm_buf_t *bp = buf_Find(dscp, &hzero);
1204                         if (bp)
1205                             buf_Release(bp);
1206                         else
1207                             code = CM_ERROR_NOSUCHFILE;
1208                     }
1209                     cm_ReleaseSCache(dscp);
1210                     if (code) {
1211                         cm_FreeSpace(spacep);
1212                         cm_ReleaseUser(userp);
1213                         smb_SendTran2Error(vcp, p, opx, code);
1214                         smb_FreeTran2Packet(outp);
1215                         return 0;
1216                     }
1217                 }
1218             }
1219         }
1220                 cm_FreeSpace(spacep);
1221         }
1222
1223         /* now do namei and stat, and copy out the info */
1224     code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1225                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1226
1227         if (code) {
1228                 cm_ReleaseUser(userp);
1229         smb_SendTran2Error(vcp, p, opx, code);
1230         smb_FreeTran2Packet(outp);
1231         return 0;
1232     }
1233
1234     lock_ObtainMutex(&scp->mx);
1235         code = cm_SyncOp(scp, NULL, userp, &req, 0,
1236                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1237         if (code) goto done;
1238         
1239     /* now we have the status in the cache entry, and everything is locked.
1240          * Marshall the output data.
1241      */
1242         op = outp->datap;
1243         /* for info level 108, figure out short name */
1244         if (infoLevel == 0x108) {
1245                 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1246                                 tidPathp, scp->fid.vnode, shortName,
1247                                 (size_t *) &len);
1248                 if (code) {
1249                         goto done;
1250                 }
1251
1252                 op = outp->datap;
1253                 *((u_long *)op) = len * 2; op += 4;
1254                 mbstowcs((unsigned short *)op, shortName, len);
1255                 op += (len * 2);
1256
1257                 goto done;
1258         }
1259         if (infoLevel == 1 || infoLevel == 2) {
1260                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1261         *((u_long *)op) = dosTime; op += 4;     /* creation time */
1262         *((u_long *)op) = dosTime; op += 4;     /* access time */
1263         *((u_long *)op) = dosTime; op += 4;     /* write time */
1264         *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1265         *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1266                 attributes = smb_Attributes(scp);
1267                 *((u_short *)op) = attributes; op += 2; /* attributes */
1268         }
1269         else if (infoLevel == 0x101) {
1270                 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1271                 *((FILETIME *)op) = ft; op += 8;        /* creation time */
1272                 *((FILETIME *)op) = ft; op += 8;        /* last access time */
1273                 *((FILETIME *)op) = ft; op += 8;        /* last write time */
1274                 *((FILETIME *)op) = ft; op += 8;        /* last change time */
1275                 extAttributes = smb_ExtAttributes(scp);
1276                 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1277                 *((u_long *)op) = 0; op += 4;   /* don't know what this is */
1278         }
1279         else if (infoLevel == 0x102) {
1280                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
1281                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
1282                 *((u_long *)op) = scp->linkCount; op += 4;
1283                 *op++ = 0;
1284                 *op++ = 0;
1285                 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1286                 *op++ = 0;
1287         }
1288         else if (infoLevel == 0x103) {
1289                 memset(op, 0, 4); op += 4;      /* EA size */
1290         }
1291
1292         /* now, if we are being asked about extended attrs, return a 0 size */
1293         if (infoLevel == 2) {
1294                 *((u_long *)op) = 0; op += 4;
1295         }
1296         
1297
1298         /* send and free the packets */
1299   done:
1300         lock_ReleaseMutex(&scp->mx);
1301     cm_ReleaseSCache(scp);
1302     cm_ReleaseUser(userp);
1303         if (code == 0) 
1304         smb_SendTran2Packet(vcp, outp, opx);
1305     else 
1306         smb_SendTran2Error(vcp, p, opx, code);
1307     smb_FreeTran2Packet(outp);
1308
1309     return 0;
1310 }
1311
1312 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1313 {
1314     return CM_ERROR_BADOP;
1315 }
1316
1317 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1318 {
1319         smb_tran2Packet_t *outp;
1320         FILETIME ft;
1321         unsigned long attributes;
1322         unsigned short infoLevel;
1323         int nbytesRequired;
1324         unsigned short fid;
1325         cm_user_t *userp;
1326     smb_fid_t *fidp;
1327         cm_scache_t *scp;
1328         char *op;
1329         long code = 0;
1330         cm_req_t req;
1331
1332         cm_InitReq(&req);
1333
1334     fid = p->parmsp[0];
1335     fidp = smb_FindFID(vcp, fid, 0);
1336
1337         if (fidp == NULL) {
1338                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
1339                 return 0;
1340         }
1341
1342         infoLevel = p->parmsp[1];
1343         if (infoLevel == 0x101) nbytesRequired = 40;
1344         else if (infoLevel == 0x102) nbytesRequired = 24;
1345         else if (infoLevel == 0x103) nbytesRequired = 4;
1346         else if (infoLevel == 0x104) nbytesRequired = 6;
1347         else {
1348                 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1349                  p->opcode, infoLevel);
1350                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1351         smb_ReleaseFID(fidp);
1352                 return 0;
1353         }
1354         osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1355
1356         outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1357
1358         if (infoLevel > 0x100)
1359                 outp->totalParms = 2;
1360         else
1361                 outp->totalParms = 0;
1362         outp->totalData = nbytesRequired;
1363
1364         userp = smb_GetTran2User(vcp, p);
1365     if(!userp) {
1366         osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
1367         code = CM_ERROR_BADSMB;
1368         goto done;
1369     }
1370
1371         scp = fidp->scp;
1372         lock_ObtainMutex(&scp->mx);
1373         code = cm_SyncOp(scp, NULL, userp, &req, 0,
1374                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1375         if (code) goto done;
1376
1377         /* now we have the status in the cache entry, and everything is locked.
1378          * Marshall the output data.
1379          */
1380         op = outp->datap;
1381         if (infoLevel == 0x101) {
1382                 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1383                 *((FILETIME *)op) = ft; op += 8;        /* creation time */
1384                 *((FILETIME *)op) = ft; op += 8;        /* last access time */
1385                 *((FILETIME *)op) = ft; op += 8;        /* last write time */
1386                 *((FILETIME *)op) = ft; op += 8;        /* last change time */
1387                 attributes = smb_ExtAttributes(scp);
1388                 *((u_long *)op) = attributes; op += 4;
1389                 *((u_long *)op) = 0; op += 4;
1390         }
1391         else if (infoLevel == 0x102) {
1392                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
1393                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
1394                 *((u_long *)op) = scp->linkCount; op += 4;
1395                 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1396                 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1397                 *op++ = 0;
1398                 *op++ = 0;
1399         }
1400         else if (infoLevel == 0x103) {
1401                 *((u_long *)op) = 0; op += 4;
1402         }
1403         else if (infoLevel == 0x104) {
1404                 unsigned long len;
1405                 char *name;
1406
1407                 if (fidp->NTopen_wholepathp)
1408                         name = fidp->NTopen_wholepathp;
1409                 else
1410                         name = "\\";    /* probably can't happen */
1411                 len = strlen(name);
1412                 outp->totalData = (len*2) + 4;  /* this is actually what we want to return */
1413                 *((u_long *)op) = len * 2; op += 4;
1414                 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1415         }
1416
1417         /* send and free the packets */
1418   done:
1419         lock_ReleaseMutex(&scp->mx);
1420         cm_ReleaseUser(userp);
1421         smb_ReleaseFID(fidp);
1422         if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1423         else smb_SendTran2Error(vcp, p, opx, code);
1424         smb_FreeTran2Packet(outp);
1425
1426         return 0;
1427 }
1428
1429 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1430 {
1431         long code = 0;
1432         unsigned short fid;
1433         smb_fid_t *fidp;
1434         unsigned short infoLevel;
1435         smb_tran2Packet_t *outp;
1436         cm_user_t *userp;
1437         cm_scache_t *scp;
1438         cm_req_t req;
1439
1440         cm_InitReq(&req);
1441
1442     fid = p->parmsp[0];
1443         fidp = smb_FindFID(vcp, fid, 0);
1444
1445         if (fidp == NULL) {
1446                 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1447                 return 0;
1448         }
1449
1450         infoLevel = p->parmsp[1];
1451         if (infoLevel > 0x104 || infoLevel < 0x101) {
1452                 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1453                          p->opcode, infoLevel);
1454                 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1455         smb_ReleaseFID(fidp);
1456                 return 0;
1457         }
1458
1459         if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1460                 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1461         smb_ReleaseFID(fidp);
1462                 return 0;
1463         }
1464         if ((infoLevel == 0x103 || infoLevel == 0x104)
1465             && !(fidp->flags & SMB_FID_OPENWRITE)) {
1466                 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1467         smb_ReleaseFID(fidp);
1468                 return 0;
1469         }
1470
1471         osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
1472
1473         outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1474
1475         outp->totalParms = 2;
1476         outp->totalData = 0;
1477
1478         userp = smb_GetTran2User(vcp, p);
1479     if(!userp) {
1480         osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
1481         code = CM_ERROR_BADSMB;
1482         goto done;
1483     }
1484
1485         scp = fidp->scp;
1486
1487         if (infoLevel == 0x101) {
1488                 FILETIME lastMod;
1489                 unsigned int attribute;
1490                 cm_attr_t attr;
1491
1492                 /* lock the vnode with a callback; we need the current status
1493                  * to determine what the new status is, in some cases.
1494                  */
1495                 lock_ObtainMutex(&scp->mx);
1496                 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1497                          CM_SCACHESYNC_GETSTATUS
1498                          | CM_SCACHESYNC_NEEDCALLBACK);
1499                 if (code) {
1500                         lock_ReleaseMutex(&scp->mx);
1501                         goto done;
1502                 }
1503
1504                 /* prepare for setattr call */
1505                 attr.mask = 0;
1506                 
1507                 lastMod = *((FILETIME *)(p->datap + 16));
1508                 /* when called as result of move a b, lastMod is (-1, -1). 
1509          * If the check for -1 is not present, timestamp
1510                  * of the resulting file will be 1969 (-1)
1511                  */
1512                 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && 
1513             lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
1514                         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1515                         smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1516                                                         &lastMod);
1517                         fidp->flags |= SMB_FID_MTIMESETDONE;
1518                 }
1519                 
1520                 attribute = *((u_long *)(p->datap + 32));
1521                 if (attribute != 0) {
1522                         if ((scp->unixModeBits & 0222)
1523                             && (attribute & 1) != 0) {
1524                                 /* make a writable file read-only */
1525                                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1526                                 attr.unixModeBits = scp->unixModeBits & ~0222;
1527                         }
1528                         else if ((scp->unixModeBits & 0222) == 0
1529                                  && (attribute & 1) == 0) {
1530                                 /* make a read-only file writable */
1531                                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1532                                 attr.unixModeBits = scp->unixModeBits | 0222;
1533                         }
1534                 }
1535                 lock_ReleaseMutex(&scp->mx);
1536
1537                 /* call setattr */
1538                 if (attr.mask)
1539                         code = cm_SetAttr(scp, &attr, userp, &req);
1540                 else
1541                         code = 0;
1542         }
1543         else if (infoLevel == 0x103 || infoLevel == 0x104) {
1544                 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1545                 cm_attr_t attr;
1546
1547                 attr.mask = CM_ATTRMASK_LENGTH;
1548                 attr.length.LowPart = size.LowPart;
1549                 attr.length.HighPart = size.HighPart;
1550                 code = cm_SetAttr(scp, &attr, userp, &req);
1551         }
1552         else if (infoLevel == 0x102) {
1553                 if (*((char *)(p->datap))) {
1554                         code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1555                                                 &req);
1556                         if (code == 0)
1557                                 fidp->flags |= SMB_FID_DELONCLOSE;
1558                 }
1559                 else {
1560                         code = 0;
1561                         fidp->flags &= ~SMB_FID_DELONCLOSE;
1562                 }
1563         }
1564   done:
1565         cm_ReleaseUser(userp);
1566         smb_ReleaseFID(fidp);
1567         if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1568         else smb_SendTran2Error(vcp, p, op, code);
1569         smb_FreeTran2Packet(outp);
1570
1571         return 0;
1572 }
1573
1574 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1575 {
1576     return CM_ERROR_BADOP;
1577 }
1578
1579 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1580 {
1581     return CM_ERROR_BADOP;
1582 }
1583
1584 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1585 {
1586     return CM_ERROR_BADOP;
1587 }
1588
1589 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1590 {
1591     return CM_ERROR_BADOP;
1592 }
1593
1594 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1595 {
1596     return CM_ERROR_BADOP;
1597 }
1598
1599 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1600         smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1601         cm_req_t *reqp)
1602 {
1603         long code = 0;
1604     cm_scache_t *scp;
1605     cm_scache_t *targetScp;                     /* target if scp is a symlink */
1606     char *dptr;
1607     long dosTime;
1608         FILETIME ft;
1609     int shortTemp;
1610     unsigned short attr;
1611         unsigned long lattr;
1612     smb_dirListPatch_t *patchp;
1613     smb_dirListPatch_t *npatchp;
1614         
1615     for(patchp = *dirPatchespp; patchp; patchp =
1616          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1617                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1618         if (code) continue;
1619         lock_ObtainMutex(&scp->mx);
1620         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1621                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1622                 if (code) { 
1623                         lock_ReleaseMutex(&scp->mx);
1624                         cm_ReleaseSCache(scp);
1625                         continue;
1626         }
1627                 
1628         /* now watch for a symlink */
1629         if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1630                         lock_ReleaseMutex(&scp->mx);
1631             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
1632             if (code == 0) {
1633                                 /* we have a more accurate file to use (the
1634                                  * target of the symbolic link).  Otherwise,
1635                                  * we'll just use the symlink anyway.
1636                  */
1637                                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
1638                          scp, targetScp);
1639                                 cm_ReleaseSCache(scp);
1640                 scp = targetScp;
1641             }
1642             lock_ObtainMutex(&scp->mx);
1643         }
1644
1645                 dptr = patchp->dptr;
1646
1647                 if (infoLevel >= 0x101) {
1648                         /* get filetime */
1649                         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1650
1651                         /* copy to Creation Time */
1652                         *((FILETIME *)dptr) = ft;
1653                         dptr += 8;
1654
1655                         /* copy to Last Access Time */
1656                         *((FILETIME *)dptr) = ft;
1657                         dptr += 8;
1658
1659                         /* copy to Last Write Time */
1660                         *((FILETIME *)dptr) = ft;
1661                         dptr += 8;
1662
1663                         /* copy to Change Time */
1664                         *((FILETIME *)dptr) = ft;
1665                         dptr += 8;
1666
1667                         /* Use length for both file length and alloc length */
1668                         *((LARGE_INTEGER *)dptr) = scp->length;
1669                         dptr += 8;
1670                         *((LARGE_INTEGER *)dptr) = scp->length;
1671                         dptr += 8;
1672
1673                         /* Copy attributes */
1674                         lattr = smb_ExtAttributes(scp);
1675             /* merge in hidden (dot file) attribute */
1676                         if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1677                                 lattr |= SMB_ATTR_HIDDEN;
1678                         *((u_long *)dptr) = lattr;
1679                         dptr += 4;
1680                 }
1681                 else {
1682                         /* get dos time */
1683                         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1684
1685                         /* and copy out date */
1686                         shortTemp = (dosTime>>16) & 0xffff;
1687                         *((u_short *)dptr) = shortTemp;
1688                         dptr += 2;
1689
1690                         /* copy out creation time */
1691                         shortTemp = dosTime & 0xffff;
1692                         *((u_short *)dptr) = shortTemp;
1693                         dptr += 2;
1694
1695                         /* and copy out date */
1696                         shortTemp = (dosTime>>16) & 0xffff;
1697                         *((u_short *)dptr) = shortTemp;
1698                         dptr += 2;
1699                         
1700                         /* copy out access time */
1701                         shortTemp = dosTime & 0xffff;
1702                         *((u_short *)dptr) = shortTemp;
1703                         dptr += 2;
1704
1705                         /* and copy out date */
1706                         shortTemp = (dosTime>>16) & 0xffff;
1707                         *((u_short *)dptr) = shortTemp;
1708                         dptr += 2;
1709                         
1710                         /* copy out mod time */
1711                         shortTemp = dosTime & 0xffff;
1712                         *((u_short *)dptr) = shortTemp;
1713                         dptr += 2;
1714
1715                         /* copy out file length and alloc length,
1716                          * using the same for both
1717                          */
1718                         *((u_long *)dptr) = scp->length.LowPart;
1719                         dptr += 4;
1720                         *((u_long *)dptr) = scp->length.LowPart;
1721                         dptr += 4;
1722
1723                         /* finally copy out attributes as short */
1724                         attr = smb_Attributes(scp);
1725             /* merge in hidden (dot file) attribute */
1726             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1727                 attr |= SMB_ATTR_HIDDEN;
1728                         *dptr++ = attr & 0xff;
1729                         *dptr++ = (attr >> 8) & 0xff;
1730                 }
1731
1732         lock_ReleaseMutex(&scp->mx);
1733         cm_ReleaseSCache(scp);
1734         }
1735         
1736     /* now free the patches */
1737     for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1738                 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1739         free(patchp);
1740         }
1741         
1742     /* and mark the list as empty */
1743     *dirPatchespp = NULL;
1744
1745     return code;
1746 }
1747
1748 /* do a case-folding search of the star name mask with the name in namep.
1749  * Return 1 if we match, otherwise 0.
1750  */
1751 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1752 {
1753         unsigned char tcp1, tcp2;       /* Pattern characters */
1754     unsigned char tcn1;         /* Name characters */
1755         int sawDot = 0, sawStar = 0, req8dot3 = 0;
1756         char *starNamep, *starMaskp;
1757         static char nullCharp[] = {0};
1758
1759         /* make sure we only match 8.3 names, if requested */
1760     req8dot3 = (flags & CM_FLAG_8DOT3);
1761         if (req8dot3 && !cm_Is8Dot3(namep)) 
1762         return 0;
1763
1764         /* loop */
1765         while (1) {
1766                 /* Next pattern character */
1767                 tcp1 = *maskp++;
1768
1769                 /* Next name character */
1770                 tcn1 = *namep;
1771
1772                 if (tcp1 == 0) {
1773                         /* 0 - end of pattern */
1774                         if (tcn1 == 0)
1775                                 return 1;
1776                         else
1777                                 return 0;
1778                 }
1779                 else if (tcp1 == '.' || tcp1 == '"') {
1780                         if (sawDot) {
1781                                 if (tcn1 == '.') {
1782                                         namep++;
1783                                         continue;
1784                                 } else
1785                                         return 0;
1786                         }
1787                         else {
1788                                 /*
1789                                  * first dot in pattern;
1790                                  * must match dot or end of name
1791                                  */
1792                                 sawDot = 1;
1793                                 if (tcn1 == 0)
1794                                         continue;
1795                                 else if (tcn1 == '.') {
1796                                         sawStar = 0;
1797                                         namep++;
1798                                         continue;
1799                                 }
1800                                 else
1801                                         return 0;
1802                         }
1803                 }
1804                 else if (tcp1 == '?') {
1805                         if (tcn1 == 0 || tcn1 == '.')
1806                                 return 0;
1807                         namep++;
1808                         continue;
1809                 }
1810                 else if (tcp1 == '>') {
1811                         if (tcn1 != 0 && tcn1 != '.')
1812                                 namep++;
1813                         continue;
1814                 }
1815                 else if (tcp1 == '*' || tcp1 == '<') {
1816                         tcp2 = *maskp++;
1817                         if (tcp2 == 0)
1818                                 return 1;
1819                         else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
1820                                 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
1821                                         tcn1 = *++namep;
1822                                 if (tcn1 == 0) {
1823                                         if (sawDot)
1824                                                 return 0;
1825                                         else
1826                                                 continue;
1827                                 }
1828                                 else {
1829                                         namep++;
1830                                         continue;
1831                                 }
1832                         }
1833                         else {
1834                                 /*
1835                                  * pattern character after '*' is not null or
1836                                  * period.  If it is '?' or '>', we are not
1837                                  * going to understand it.  If it is '*' or
1838                                  * '<', we are going to skip over it.  None of
1839                                  * these are likely, I hope.
1840                                  */
1841                                 /* skip over '*' and '<' */
1842                                 while (tcp2 == '*' || tcp2 == '<')
1843                                         tcp2 = *maskp++;
1844
1845                                 /* skip over characters that don't match tcp2 */
1846                                 while (req8dot3 && tcn1 != '.' && tcn1 != 0
1847                                         && cm_foldUpper[tcn1] != cm_foldUpper[tcp2])
1848                                         tcn1 = *++namep;
1849
1850                                 /* No match */
1851                                 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
1852                                         return 0;
1853
1854                                 /* Remember where we are */
1855                                 sawStar = 1;
1856                                 starMaskp = maskp;
1857                                 starNamep = namep;
1858
1859                                 namep++;
1860                                 continue;
1861                         }
1862                 }
1863                 else {
1864                         /* tcp1 is not a wildcard */
1865                         if (cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) {
1866                                 /* they match */
1867                                 namep++;
1868                                 continue;
1869                         }
1870                         /* if trying to match a star pattern, go back */
1871                         if (sawStar) {
1872                                 maskp = starMaskp - 2;
1873                                 namep = starNamep + 1;
1874                                 sawStar = 0;
1875                                 continue;
1876                         }
1877                         /* that's all */
1878                         return 0;
1879                 }
1880         }
1881 }
1882
1883 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1884 {
1885         int attribute;
1886     long nextCookie;
1887     char *tp;
1888     long code = 0;
1889     char *pathp;
1890     cm_dirEntry_t *dep;
1891     int maxCount;
1892     smb_dirListPatch_t *dirListPatchesp;
1893     smb_dirListPatch_t *curPatchp;
1894     cm_buf_t *bufferp;
1895     long temp;
1896     long orbytes;                       /* # of bytes in this output record */
1897     long ohbytes;                       /* # of bytes, except file name */
1898     long onbytes;                       /* # of bytes in name, incl. term. null */
1899     osi_hyper_t dirLength;
1900     osi_hyper_t bufferOffset;
1901     osi_hyper_t curOffset;
1902     osi_hyper_t thyper;
1903     smb_dirSearch_t *dsp;
1904     cm_scache_t *scp;
1905     long entryInDir;
1906     long entryInBuffer;
1907         cm_pageHeader_t *pageHeaderp;
1908     cm_user_t *userp = NULL;
1909     int slotInPage;
1910     int returnedNames;
1911     long nextEntryCookie;
1912     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
1913     char *op;                   /* output data ptr */
1914         char *origOp;                   /* original value of op */
1915     cm_space_t *spacep;         /* for pathname buffer */
1916     long maxReturnData;         /* max # of return data */
1917     long maxReturnParms;                /* max # of return parms */
1918     long bytesInBuffer;         /* # data bytes in the output buffer */
1919     int starPattern;
1920     char *maskp;                        /* mask part of path */
1921     int infoLevel;
1922     int searchFlags;
1923     int eos;
1924     smb_tran2Packet_t *outp;    /* response packet */
1925         char *tidPathp;
1926         int align;
1927         char shortName[13];             /* 8.3 name if needed */
1928         int NeedShortName;
1929         char *shortNameEnd;
1930     int fileType;
1931     cm_fid_t fid;
1932
1933     cm_req_t req;
1934
1935         cm_InitReq(&req);
1936
1937         eos = 0;
1938         if (p->opcode == 1) {
1939                 /* find first; obtain basic parameters from request */
1940         attribute = p->parmsp[0];
1941         maxCount = p->parmsp[1];
1942         infoLevel = p->parmsp[3];
1943         searchFlags = p->parmsp[2];
1944         dsp = smb_NewDirSearch(1);
1945         dsp->attribute = attribute;
1946         pathp = ((char *) p->parmsp) + 12;      /* points to path */
1947         nextCookie = 0;
1948         maskp = strrchr(pathp, '\\');
1949         if (maskp == NULL) maskp = pathp;
1950                 else maskp++;   /* skip over backslash */
1951         strcpy(dsp->mask, maskp);       /* and save mask */
1952                 /* track if this is likely to match a lot of entries */
1953         starPattern = smb_V3IsStarMask(maskp);
1954         }
1955     else {
1956                 osi_assert(p->opcode == 2);
1957         /* find next; obtain basic parameters from request or open dir file */
1958         dsp = smb_FindDirSearch(p->parmsp[0]);
1959         if (!dsp) return CM_ERROR_BADFD;
1960         attribute = dsp->attribute;
1961         maxCount = p->parmsp[1];
1962         infoLevel = p->parmsp[2];
1963         searchFlags = p->parmsp[5];
1964         pathp = NULL;
1965         nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
1966         maskp = dsp->mask;
1967                 starPattern = 1;        /* assume, since required a Find Next */
1968     }
1969
1970         osi_Log4(smb_logp,
1971               "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
1972               attribute, infoLevel, maxCount, searchFlags);
1973
1974         osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
1975               p->opcode, nextCookie);
1976
1977         if (infoLevel >= 0x101)
1978                 searchFlags &= ~4;      /* no resume keys */
1979
1980     dirListPatchesp = NULL;
1981
1982         maxReturnData = p->maxReturnData;
1983     if (p->opcode == 1) /* find first */
1984         maxReturnParms = 10;    /* bytes */
1985         else    
1986         maxReturnParms = 8;     /* bytes */
1987
1988 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
1989     if (maxReturnData > 6000) 
1990         maxReturnData = 6000;
1991 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
1992
1993         outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
1994                                       maxReturnData);
1995
1996     osi_Log1(smb_logp, "T2 receive search dir %s",
1997              osi_LogSaveString(smb_logp, pathp));
1998         
1999     /* bail out if request looks bad */
2000     if (p->opcode == 1 && !pathp) {
2001         smb_ReleaseDirSearch(dsp);
2002         smb_FreeTran2Packet(outp);
2003         return CM_ERROR_BADSMB;
2004     }
2005         
2006         osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
2007              nextCookie, dsp->cookie);
2008
2009         userp = smb_GetTran2User(vcp, p);
2010     if (!userp) {
2011         osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
2012         smb_ReleaseDirSearch(dsp);
2013         smb_FreeTran2Packet(outp);
2014         return CM_ERROR_BADSMB;
2015     }
2016
2017         /* try to get the vnode for the path name next */
2018         lock_ObtainMutex(&dsp->mx);
2019         if (dsp->scp) {
2020                 scp = dsp->scp;
2021         cm_HoldSCache(scp);
2022         code = 0;
2023     }
2024     else {
2025                 spacep = cm_GetSpace();
2026         smb_StripLastComponent(spacep->data, NULL, pathp);
2027         lock_ReleaseMutex(&dsp->mx);
2028
2029                 tidPathp = smb_GetTIDPath(vcp, p->tid);
2030         code = cm_NameI(cm_rootSCachep, spacep->data,
2031                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2032                         userp, tidPathp, &req, &scp);
2033         cm_FreeSpace(spacep);
2034
2035         lock_ObtainMutex(&dsp->mx);
2036                 if (code == 0) {
2037             if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2038                         dsp->scp = scp;
2039                         /* we need one hold for the entry we just stored into,
2040              * and one for our own processing.  When we're done
2041                          * with this function, we'll drop the one for our own
2042                          * processing.  We held it once from the namei call,
2043                          * and so we do another hold now.
2044              */
2045             cm_HoldSCache(scp);
2046                         lock_ObtainMutex(&scp->mx);
2047                         if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2048                             && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2049                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2050                                 dsp->flags |= SMB_DIRSEARCH_BULKST;
2051                         }
2052                         lock_ReleaseMutex(&scp->mx);
2053         }
2054     }
2055         lock_ReleaseMutex(&dsp->mx);
2056     if (code) {
2057                 cm_ReleaseUser(userp);
2058         smb_FreeTran2Packet(outp);
2059                 smb_DeleteDirSearch(dsp);
2060                 smb_ReleaseDirSearch(dsp);
2061         return code;
2062         }
2063
2064     /* get the directory size */
2065         lock_ObtainMutex(&scp->mx);
2066     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2067                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2068         if (code) {
2069                 lock_ReleaseMutex(&scp->mx);
2070         cm_ReleaseSCache(scp);
2071         cm_ReleaseUser(userp);
2072         smb_FreeTran2Packet(outp);
2073                 smb_DeleteDirSearch(dsp);
2074                 smb_ReleaseDirSearch(dsp);
2075         return code;
2076     }
2077
2078     dirLength = scp->length;
2079     bufferp = NULL;
2080     bufferOffset.LowPart = bufferOffset.HighPart = 0;
2081     curOffset.HighPart = 0;
2082     curOffset.LowPart = nextCookie;
2083         origOp = outp->datap;
2084
2085     code = 0;
2086     returnedNames = 0;
2087     bytesInBuffer = 0;
2088     while (1) {
2089                 op = origOp;
2090                 if (searchFlags & 4)
2091                         /* skip over resume key */
2092                         op += 4;
2093
2094                 /* make sure that curOffset.LowPart doesn't point to the first
2095          * 32 bytes in the 2nd through last dir page, and that it doesn't
2096          * point at the first 13 32-byte chunks in the first dir page,
2097          * since those are dir and page headers, and don't contain useful
2098          * information.
2099          */
2100                 temp = curOffset.LowPart & (2048-1);
2101         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2102                         /* we're in the first page */
2103             if (temp < 13*32) temp = 13*32;
2104                 }
2105                 else {
2106                         /* we're in a later dir page */
2107             if (temp < 32) temp = 32;
2108         }
2109                 
2110         /* make sure the low order 5 bits are zero */
2111         temp &= ~(32-1);
2112                 
2113         /* now put temp bits back ito curOffset.LowPart */
2114         curOffset.LowPart &= ~(2048-1);
2115         curOffset.LowPart |= temp;
2116
2117         /* check if we've passed the dir's EOF */
2118         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2119             eos = 1;
2120             break;
2121         }
2122
2123         /* check if we've returned all the names that will fit in the
2124          * response packet; we check return count as well as the number
2125          * of bytes requested.  We check the # of bytes after we find
2126          * the dir entry, since we'll need to check its size.
2127          */
2128         if (returnedNames >= maxCount) {
2129             break;
2130         }
2131
2132         /* see if we can use the bufferp we have now; compute in which
2133          * page the current offset would be, and check whether that's
2134          * the offset of the buffer we have.  If not, get the buffer.
2135          */
2136         thyper.HighPart = curOffset.HighPart;
2137         thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2138         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2139                         /* wrong buffer */
2140             if (bufferp) {
2141                 buf_Release(bufferp);
2142                 bufferp = NULL;
2143                         }       
2144                         lock_ReleaseMutex(&scp->mx);
2145                         lock_ObtainRead(&scp->bufCreateLock);
2146             code = buf_Get(scp, &thyper, &bufferp);
2147                         lock_ReleaseRead(&scp->bufCreateLock);
2148
2149                         /* now, if we're doing a star match, do bulk fetching
2150                          * of all of the status info for files in the dir.
2151              */
2152             if (starPattern) {
2153                                 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2154                                           infoLevel, userp,
2155                                           &req);
2156                                 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2157                     && LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
2158                                         /* Don't bulk stat if risking timeout */
2159                                         int now = GetCurrentTime();
2160                                         if (now - req.startTime > 5000) {
2161                                                 scp->bulkStatProgress = thyper;
2162                                                 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2163                                                 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2164                                         } else
2165                         cm_TryBulkStat(scp, &thyper, userp, &req);
2166                                 }
2167                         }
2168
2169             lock_ObtainMutex(&scp->mx);
2170             if (code) break;
2171             bufferOffset = thyper;
2172
2173             /* now get the data in the cache */
2174             while (1) {
2175                                 code = cm_SyncOp(scp, bufferp, userp, &req,
2176                                  PRSFS_LOOKUP,
2177                                  CM_SCACHESYNC_NEEDCALLBACK
2178                                  | CM_SCACHESYNC_READ);
2179                                 if (code) break;
2180                                 
2181                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2182
2183                 /* otherwise, load the buffer and try again */
2184                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2185                                     &req);
2186                 if (code) break;
2187             }
2188             if (code) {
2189                                 buf_Release(bufferp);
2190                 bufferp = NULL;
2191                 break;
2192                         }
2193         }       /* if (wrong buffer) ... */
2194                 
2195         /* now we have the buffer containing the entry we're interested
2196          * in; copy it out if it represents a non-deleted entry.
2197          */
2198                 entryInDir = curOffset.LowPart & (2048-1);
2199         entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2200
2201                 /* page header will help tell us which entries are free.  Page
2202                  * header can change more often than once per buffer, since
2203                  * AFS 3 dir page size may be less than (but not more than)
2204                  * a buffer package buffer.
2205          */
2206                 /* only look intra-buffer */
2207                 temp = curOffset.LowPart & (buf_bufferSize - 1);
2208         temp &= ~(2048 - 1);    /* turn off intra-page bits */
2209                 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2210
2211                 /* now determine which entry we're looking at in the page.
2212                  * If it is free (there's a free bitmap at the start of the
2213                  * dir), we should skip these 32 bytes.
2214          */
2215         slotInPage = (entryInDir & 0x7e0) >> 5;
2216         if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2217                & (1 << (slotInPage & 0x7)))) {
2218                         /* this entry is free */
2219             numDirChunks = 1;   /* only skip this guy */
2220             goto nextEntry;
2221         }
2222
2223                 tp = bufferp->datap + entryInBuffer;
2224         dep = (cm_dirEntry_t *) tp;     /* now points to AFS3 dir entry */
2225
2226         /* while we're here, compute the next entry's location, too,
2227                  * since we'll need it when writing out the cookie into the dir
2228                  * listing stream.
2229          *
2230          * XXXX Probably should do more sanity checking.
2231          */
2232                 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2233                 
2234         /* compute offset of cookie representing next entry */
2235         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
2236
2237                 /* Need 8.3 name? */
2238                 NeedShortName = 0;
2239                 if (infoLevel == 0x104
2240                     && dep->fid.vnode != 0
2241                     && !cm_Is8Dot3(dep->name)) {
2242                         cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2243                         NeedShortName = 1;
2244                 }
2245
2246         if (dep->fid.vnode != 0
2247              && (smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)
2248                  || (NeedShortName
2249                       && smb_V3MatchMask(shortName, maskp,
2250                                           CM_FLAG_CASEFOLD)))) {
2251
2252             /* Eliminate entries that don't match requested attributes */
2253             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && 
2254                  smb_IsDotFile(dep->name))
2255                 goto nextEntry; /* no hidden files */
2256                     
2257             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
2258             {
2259                 /* We have already done the cm_TryBulkStat above */
2260                 fid.cell = scp->fid.cell;
2261                 fid.volume = scp->fid.volume;
2262                 fid.vnode = ntohl(dep->fid.vnode);
2263                 fid.unique = ntohl(dep->fid.unique);
2264                 fileType = cm_FindFileType(&fid);
2265                 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
2266                  "has filetype %d", dep->name,
2267                  fileType);*/
2268                 if (fileType == CM_SCACHETYPE_DIRECTORY)
2269                     goto nextEntry;
2270             }
2271
2272                         /* finally check if this name will fit */
2273
2274                         /* standard dir entry stuff */
2275                         if (infoLevel < 0x101)
2276                                 ohbytes = 23;   /* pre-NT */
2277                         else if (infoLevel == 0x103)
2278                                 ohbytes = 12;   /* NT names only */
2279                         else
2280                                 ohbytes = 64;   /* NT */
2281
2282                         if (infoLevel == 0x104)
2283                                 ohbytes += 26;  /* Short name & length */
2284
2285             if (searchFlags & 4) {
2286                 ohbytes += 4;   /* if resume key required */
2287                         }   
2288
2289             if (infoLevel != 1
2290                  && infoLevel != 0x101
2291                  && infoLevel != 0x103)
2292                                 ohbytes += 4;   /* EASIZE */
2293
2294                         /* add header to name & term. null */
2295                         orbytes = onbytes + ohbytes + 1;
2296
2297                         /* now, we round up the record to a 4 byte alignment,
2298                          * and we make sure that we have enough room here for
2299                          * even the aligned version (so we don't have to worry
2300                          * about an * overflow when we pad things out below).
2301                          * That's the reason for the alignment arithmetic below.
2302              */
2303                         if (infoLevel >= 0x101)
2304                                 align = (4 - (orbytes & 3)) & 3;
2305                         else
2306                                 align = 0;
2307                         if (orbytes + bytesInBuffer + align > maxReturnData)
2308                 break;
2309
2310                         /* this is one of the entries to use: it is not deleted
2311                          * and it matches the star pattern we're looking for.
2312                          * Put out the name, preceded by its length.
2313              */
2314                         /* First zero everything else */
2315                         memset(origOp, 0, ohbytes);
2316
2317                         if (infoLevel <= 0x101)
2318                 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2319                         else if (infoLevel == 0x103)
2320                                 *((u_long *)(op + 8)) = onbytes;
2321                         else
2322                                 *((u_long *)(op + 60)) = onbytes;
2323             strcpy(origOp+ohbytes, dep->name);
2324
2325                         /* Short name if requested and needed */
2326             if (infoLevel == 0x104) {
2327                                 if (NeedShortName) {
2328                                         strcpy(op + 70, shortName);
2329                                         *(op + 68) = shortNameEnd - shortName;
2330                                 }
2331                         }
2332
2333             /* now, adjust the # of entries copied */
2334             returnedNames++;
2335
2336                         /* NextEntryOffset and FileIndex */
2337                         if (infoLevel >= 101) {
2338                                 int entryOffset = orbytes + align;
2339                                 *((u_long *)op) = entryOffset;
2340                                 *((u_long *)(op+4)) = nextEntryCookie;
2341                         }
2342
2343             /* now we emit the attribute.  This is tricky, since
2344              * we need to really stat the file to find out what
2345                          * type of entry we've got.  Right now, we're copying
2346                          * out data from * a buffer, while holding the scp
2347                          * locked, so it isn't really convenient to stat
2348                          * something now.  We'll put in a place holder
2349              * now, and make a second pass before returning this
2350                          * to get the real attributes.  So, we just skip the
2351                          * data for now, and adjust it later.  We allocate a
2352                          * patch record to make it easy to find this point
2353                          * later.  The replay will happen at a time when it is
2354                          * safe to unlock the directory.
2355              */
2356                         if (infoLevel != 0x103) {
2357                                 curPatchp = malloc(sizeof(*curPatchp));
2358                 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2359                           &curPatchp->q);
2360                                 curPatchp->dptr = op;
2361                                 if (infoLevel >= 0x101)
2362                                         curPatchp->dptr += 8;
2363
2364                 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
2365                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
2366                 }
2367                 else
2368                     curPatchp->flags = 0;
2369
2370                                 curPatchp->fid.cell = scp->fid.cell;
2371                                 curPatchp->fid.volume = scp->fid.volume;
2372                                 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2373                                 curPatchp->fid.unique = ntohl(dep->fid.unique);
2374
2375                 /* temp */
2376                 curPatchp->dep = dep;
2377                         }   
2378
2379                         if (searchFlags & 4)
2380                                 /* put out resume key */
2381                                 *((u_long *)origOp) = nextEntryCookie;
2382
2383                         /* Adjust byte ptr and count */
2384                         origOp += orbytes;      /* skip entire record */
2385             bytesInBuffer += orbytes;
2386
2387                         /* and pad the record out */
2388             while (--align >= 0) {
2389                                 *origOp++ = 0;
2390                 bytesInBuffer++;
2391             }
2392
2393                 }       /* if we're including this name */
2394                 
2395       nextEntry:
2396         /* and adjust curOffset to be where the new cookie is */
2397                 thyper.HighPart = 0;
2398         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2399         curOffset = LargeIntegerAdd(thyper, curOffset);
2400     }           /* while copying data for dir listing */
2401
2402         /* release the mutex */
2403         lock_ReleaseMutex(&scp->mx);
2404     if (bufferp) buf_Release(bufferp);
2405
2406         /* apply and free last set of patches; if not doing a star match, this
2407          * will be empty, but better safe (and freeing everything) than sorry.
2408      */
2409     smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2410                               &req);
2411         
2412     /* now put out the final parameters */
2413         if (returnedNames == 0) eos = 1;
2414     if (p->opcode == 1) {
2415                 /* find first */
2416         outp->parmsp[0] = (unsigned short) dsp->cookie;
2417         outp->parmsp[1] = returnedNames;
2418         outp->parmsp[2] = eos;
2419         outp->parmsp[3] = 0;            /* nothing wrong with EAS */
2420         outp->parmsp[4] = 0;    
2421         /* don't need last name to continue
2422          * search, cookie is enough.  Normally,
2423          * this is the offset of the file name
2424          * of the last entry returned.
2425          */
2426         outp->totalParms = 10;  /* in bytes */
2427     }
2428     else {
2429         /* find next */
2430         outp->parmsp[0] = returnedNames;
2431         outp->parmsp[1] = eos;
2432         outp->parmsp[2] = 0;    /* EAS error */
2433         outp->parmsp[3] = 0;    /* last name, as above */
2434         outp->totalParms = 8;   /* in bytes */
2435     }   
2436
2437         /* return # of bytes in the buffer */
2438     outp->totalData = bytesInBuffer;
2439
2440         osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
2441               returnedNames, code);
2442
2443         /* Return error code if unsuccessful on first request */
2444         if (code == 0 && p->opcode == 1 && returnedNames == 0)
2445                 code = CM_ERROR_NOSUCHFILE;
2446
2447         /* if we're supposed to close the search after this request, or if
2448      * we're supposed to close the search if we're done, and we're done,
2449      * or if something went wrong, close the search.
2450      */
2451     /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2452         if ((searchFlags & 1) || (returnedNames == 0) || 
2453          ((searchFlags & 2) && eos) || code != 0)
2454             smb_DeleteDirSearch(dsp);
2455         if (code)
2456         smb_SendTran2Error(vcp, p, opx, code);
2457         else {
2458         smb_SendTran2Packet(vcp, outp, opx);
2459         }
2460         smb_FreeTran2Packet(outp);
2461     smb_ReleaseDirSearch(dsp);
2462     cm_ReleaseSCache(scp);
2463     cm_ReleaseUser(userp);
2464     return 0;
2465 }
2466
2467 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2468 {
2469     int dirHandle;
2470     smb_dirSearch_t *dsp;
2471
2472     dirHandle = smb_GetSMBParm(inp, 0);
2473         
2474     osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
2475
2476     dsp = smb_FindDirSearch(dirHandle);
2477         
2478     if (!dsp)
2479                 return CM_ERROR_BADFD;
2480         
2481     /* otherwise, we have an FD to destroy */
2482     smb_DeleteDirSearch(dsp);
2483     smb_ReleaseDirSearch(dsp);
2484         
2485         /* and return results */
2486         smb_SetSMBDataLength(outp, 0);
2487
2488     return 0;
2489 }
2490
2491 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2492 {
2493         smb_SetSMBDataLength(outp, 0);
2494     return 0;
2495 }
2496
2497 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2498 {
2499         char *pathp;
2500     long code = 0;
2501         cm_space_t *spacep;
2502     int excl;
2503     cm_user_t *userp;
2504     cm_scache_t *dscp;          /* dir we're dealing with */
2505     cm_scache_t *scp;           /* file we're creating */
2506     cm_attr_t setAttr;
2507     int initialModeBits;
2508     smb_fid_t *fidp;
2509     int attributes;
2510     char *lastNamep;
2511     long dosTime;
2512     int openFun;
2513     int trunc;
2514     int openMode;
2515     int extraInfo;
2516     int openAction;
2517     int parmSlot;                       /* which parm we're dealing with */
2518         char *tidPathp;
2519         cm_req_t req;
2520
2521         cm_InitReq(&req);
2522
2523     scp = NULL;
2524         
2525         extraInfo = (smb_GetSMBParm(inp, 2) & 1);       /* return extra info */
2526         openFun = smb_GetSMBParm(inp, 8);       /* open function */
2527     excl = ((openFun & 3) == 0);
2528     trunc = ((openFun & 3) == 2);               /* truncate it */
2529         openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2530     openAction = 0;                     /* tracks what we did */
2531
2532     attributes = smb_GetSMBParm(inp, 5);
2533     dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2534
2535         /* compute initial mode bits based on read-only flag in attributes */
2536     initialModeBits = 0666;
2537     if (attributes & 1) initialModeBits &= ~0222;
2538         
2539     pathp = smb_GetSMBData(inp, NULL);
2540
2541         spacep = inp->spacep;
2542     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2543
2544         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2545                 /* special case magic file name for receiving IOCTL requests
2546          * (since IOCTL calls themselves aren't getting through).
2547          */
2548 #ifdef NOTSERVICE
2549         osi_Log0(smb_logp, "IOCTL Open");
2550 #endif
2551
2552         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2553         smb_SetupIoctlFid(fidp, spacep);
2554
2555                 /* set inp->fid so that later read calls in same msg can find fid */
2556         inp->fid = fidp->fid;
2557         
2558         /* copy out remainder of the parms */
2559                 parmSlot = 2;
2560                 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2561                 if (extraInfo) {
2562             smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2563             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* mod time */
2564             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2565             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* len */
2566             smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2567             smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2568             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2569             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2570                 }   
2571                 /* and the final "always present" stuff */
2572         smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2573                 /* next write out the "unique" ID */
2574                 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2575                 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2576         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2577         smb_SetSMBDataLength(outp, 0);
2578
2579                 /* and clean up fid reference */
2580         smb_ReleaseFID(fidp);
2581         return 0;
2582     }
2583
2584 #ifdef DEBUG_VERBOSE
2585     {
2586         char *hexp, *asciip;
2587         asciip = (lastNamep ? lastNamep : pathp );
2588         hexp = osi_HexifyString(asciip);
2589         DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
2590         free(hexp);
2591     }
2592 #endif
2593     userp = smb_GetUser(vcp, inp);
2594
2595         dscp = NULL;
2596         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2597         code = cm_NameI(cm_rootSCachep, pathp,
2598                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2599                     userp, tidPathp, &req, &scp);
2600         if (code != 0) {
2601                 code = cm_NameI(cm_rootSCachep, spacep->data,
2602                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2603                         userp, tidPathp, &req, &dscp);
2604
2605         if (code) {
2606             cm_ReleaseUser(userp);
2607             return code;
2608         }
2609         
2610         /* otherwise, scp points to the parent directory.  Do a lookup,
2611          * and truncate the file if we find it, otherwise we create the
2612          * file.
2613          */
2614         if (!lastNamep) lastNamep = pathp;
2615         else lastNamep++;
2616         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2617                           &req, &scp);
2618         if (code && code != CM_ERROR_NOSUCHFILE) {
2619                         cm_ReleaseSCache(dscp);
2620             cm_ReleaseUser(userp);
2621             return code;
2622         }
2623         }
2624         
2625     /* if we get here, if code is 0, the file exists and is represented by
2626      * scp.  Otherwise, we have to create it.  The dir may be represented
2627      * by dscp, or we may have found the file directly.  If code is non-zero,
2628      * scp is NULL.
2629      */
2630         if (code == 0) {
2631         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2632         if (code) {
2633             if (dscp) cm_ReleaseSCache(dscp);
2634             cm_ReleaseSCache(scp);
2635             cm_ReleaseUser(userp);
2636             return code;
2637         }
2638
2639                 if (excl) {
2640                         /* oops, file shouldn't be there */
2641             if (dscp) cm_ReleaseSCache(dscp);
2642             cm_ReleaseSCache(scp);
2643             cm_ReleaseUser(userp);
2644             return CM_ERROR_EXISTS;
2645         }
2646
2647                 if (trunc) {
2648                         setAttr.mask = CM_ATTRMASK_LENGTH;
2649             setAttr.length.LowPart = 0;
2650             setAttr.length.HighPart = 0;
2651                         code = cm_SetAttr(scp, &setAttr, userp, &req);
2652             openAction = 3;     /* truncated existing file */
2653                 }
2654         else openAction = 1;    /* found existing file */
2655     }
2656         else if (!(openFun & 0x10)) {
2657                 /* don't create if not found */
2658         if (dscp) cm_ReleaseSCache(dscp);
2659         cm_ReleaseUser(userp);
2660         return CM_ERROR_NOSUCHFILE;
2661     }
2662     else {
2663                 osi_assert(dscp != NULL);
2664                 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
2665                  osi_LogSaveString(smb_logp, lastNamep));
2666                 openAction = 2; /* created file */
2667                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2668                 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2669         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2670                          &req);
2671                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2672                         smb_NotifyChange(FILE_ACTION_ADDED,
2673                              FILE_NOTIFY_CHANGE_FILE_NAME,
2674                              dscp, lastNamep, NULL, TRUE);
2675         if (!excl && code == CM_ERROR_EXISTS) {
2676                         /* not an exclusive create, and someone else tried
2677                          * creating it already, then we open it anyway.  We
2678                          * don't bother retrying after this, since if this next
2679                          * fails, that means that the file was deleted after we
2680                          * started this call.
2681              */
2682             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2683                              userp, &req, &scp);
2684             if (code == 0) {
2685                 if (trunc) {
2686                                         setAttr.mask = CM_ATTRMASK_LENGTH;
2687                     setAttr.length.LowPart = 0;
2688                     setAttr.length.HighPart = 0;
2689                     code = cm_SetAttr(scp, &setAttr, userp, &req);
2690                 }   
2691                         }       /* lookup succeeded */
2692         }
2693     }
2694         
2695         /* we don't need this any longer */
2696         if (dscp) cm_ReleaseSCache(dscp);
2697
2698     if (code) {
2699                 /* something went wrong creating or truncating the file */
2700         if (scp) cm_ReleaseSCache(scp);
2701         cm_ReleaseUser(userp);
2702         return code;
2703     }
2704         
2705         /* make sure we're about to open a file */
2706         if (scp->fileType != CM_SCACHETYPE_FILE) {
2707                 cm_ReleaseSCache(scp);
2708                 cm_ReleaseUser(userp);
2709                 return CM_ERROR_ISDIR;
2710         }
2711
2712     /* now all we have to do is open the file itself */
2713     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2714     osi_assert(fidp);
2715         
2716         /* save a pointer to the vnode */
2717     fidp->scp = scp;
2718         
2719         /* compute open mode */
2720     if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2721     if (openMode == 1 || openMode == 2)
2722         fidp->flags |= SMB_FID_OPENWRITE;
2723
2724         smb_ReleaseFID(fidp);
2725         
2726         cm_Open(scp, 0, userp);
2727
2728         /* set inp->fid so that later read calls in same msg can find fid */
2729     inp->fid = fidp->fid;
2730         
2731     /* copy out remainder of the parms */
2732         parmSlot = 2;
2733         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2734         lock_ObtainMutex(&scp->mx);
2735         if (extraInfo) {
2736         smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2737                 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2738         smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2739         smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2740         smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2741         smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2742         smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2743         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2744         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2745         }
2746         /* and the final "always present" stuff */
2747     smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2748         /* next write out the "unique" ID */
2749         smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2750         smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2751     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2752         lock_ReleaseMutex(&scp->mx);
2753     smb_SetSMBDataLength(outp, 0);
2754
2755         osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
2756
2757     cm_ReleaseUser(userp);
2758     /* leave scp held since we put it in fidp->scp */
2759     return 0;
2760 }   
2761
2762 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2763 {
2764         cm_req_t req;
2765         cm_user_t *userp;
2766         unsigned short fid;
2767         smb_fid_t *fidp;
2768         cm_scache_t *scp;
2769         unsigned char LockType;
2770         unsigned short NumberOfUnlocks, NumberOfLocks;
2771         unsigned long Timeout;
2772         char *op;
2773         LARGE_INTEGER LOffset, LLength;
2774         smb_waitingLock_t *waitingLock;
2775         void *lockp;
2776         long code = 0;
2777         int i;
2778
2779         cm_InitReq(&req);
2780
2781         fid = smb_GetSMBParm(inp, 2);
2782         fid = smb_ChainFID(fid, inp);
2783
2784         fidp = smb_FindFID(vcp, fid, 0);
2785         if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2786                 return CM_ERROR_BADFD;
2787         }
2788         /* set inp->fid so that later read calls in same msg can find fid */
2789     inp->fid = fid;
2790
2791         userp = smb_GetUser(vcp, inp);
2792
2793         scp = fidp->scp;
2794
2795         lock_ObtainMutex(&scp->mx);
2796         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2797                          CM_SCACHESYNC_NEEDCALLBACK
2798                          | CM_SCACHESYNC_GETSTATUS
2799                          | CM_SCACHESYNC_LOCK);
2800         if (code) goto doneSync;
2801
2802         LockType = smb_GetSMBParm(inp, 3) & 0xff;
2803         Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2804         NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2805         NumberOfLocks = smb_GetSMBParm(inp, 7);
2806
2807         op = smb_GetSMBData(inp, NULL);
2808
2809         for (i=0; i<NumberOfUnlocks; i++) {
2810                 if (LockType & 0x10) {
2811                         /* Large Files */
2812                         LOffset.HighPart = *((LONG *)(op + 4));
2813                         LOffset.LowPart = *((DWORD *)(op + 8));
2814                         LLength.HighPart = *((LONG *)(op + 12));
2815                         LLength.LowPart = *((DWORD *)(op + 16));
2816                         op += 20;
2817                 }
2818                 else {
2819                         /* Not Large Files */
2820                         LOffset.HighPart = 0;
2821                         LOffset.LowPart = *((DWORD *)(op + 2));
2822                         LLength.HighPart = 0;
2823                         LLength.LowPart = *((DWORD *)(op + 6));
2824                         op += 10;
2825                 }
2826                 if (LargeIntegerNotEqualToZero(LOffset))
2827                         continue;
2828                 /* Do not check length -- length check done in cm_Unlock */
2829
2830                 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2831                 if (code) goto done;
2832         }
2833
2834         for (i=0; i<NumberOfLocks; i++) {
2835                 if (LockType & 0x10) {
2836                         /* Large Files */
2837                         LOffset.HighPart = *((LONG *)(op + 4));
2838                         LOffset.LowPart = *((DWORD *)(op + 8));
2839                         LLength.HighPart = *((LONG *)(op + 12));
2840                         LLength.LowPart = *((DWORD *)(op + 16));
2841                         op += 20;
2842                 }
2843                 else {
2844                         /* Not Large Files */
2845                         LOffset.HighPart = 0;
2846                         LOffset.LowPart = *((DWORD *)(op + 2));
2847                         LLength.HighPart = 0;
2848                         LLength.LowPart = *((DWORD *)(op + 6));
2849                         op += 10;
2850                 }
2851                 if (LargeIntegerNotEqualToZero(LOffset))
2852                         continue;
2853                 if (LargeIntegerLessThan(LOffset, scp->length))
2854                         continue;
2855
2856                 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2857                                 userp, &req, &lockp);
2858                 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2859                         /* Put on waiting list */
2860                         waitingLock = malloc(sizeof(smb_waitingLock_t));
2861                         waitingLock->vcp = vcp;
2862                         waitingLock->inp = smb_CopyPacket(inp);
2863                         waitingLock->outp = smb_CopyPacket(outp);
2864                         waitingLock->timeRemaining = Timeout;
2865                         waitingLock->lockp = lockp;
2866                         lock_ObtainWrite(&smb_globalLock);
2867                         osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2868                                  &waitingLock->q);
2869                         osi_Wakeup((long) &smb_allWaitingLocks);
2870                         lock_ReleaseWrite(&smb_globalLock);
2871                         /* don't send reply immediately */
2872                         outp->flags |= SMB_PACKETFLAG_NOSEND;
2873                 }
2874                 if (code) break;
2875         }
2876
2877         if (code) {
2878                 /* release any locks acquired before the failure */
2879         }
2880         else
2881                 smb_SetSMBDataLength(outp, 0);
2882 done:
2883         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2884 doneSync:
2885         lock_ReleaseMutex(&scp->mx);
2886         cm_ReleaseUser(userp);
2887         smb_ReleaseFID(fidp);
2888
2889         return code;
2890 }
2891
2892 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2893 {
2894         unsigned short fid;
2895     smb_fid_t *fidp;
2896     cm_scache_t *scp;
2897     long code = 0;
2898     long searchTime;
2899     cm_user_t *userp;
2900         cm_req_t req;
2901
2902         cm_InitReq(&req);
2903
2904     fid = smb_GetSMBParm(inp, 0);
2905     fid = smb_ChainFID(fid, inp);
2906         
2907     fidp = smb_FindFID(vcp, fid, 0);
2908     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2909                 return CM_ERROR_BADFD;
2910     }
2911         
2912     userp = smb_GetUser(vcp, inp);
2913         
2914     scp = fidp->scp;
2915         
2916     /* otherwise, stat the file */
2917         lock_ObtainMutex(&scp->mx);
2918     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2919                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2920         if (code) goto done;
2921
2922         /* decode times.  We need a search time, but the response to this
2923      * call provides the date first, not the time, as returned in the
2924      * searchTime variable.  So we take the high-order bits first.
2925      */
2926         smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2927     smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff);       /* ctime */
2928     smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2929     smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff);       /* atime */
2930     smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2931     smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff);       /* mtime */
2932     smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2933
2934     /* now handle file size and allocation size */
2935     smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff);              /* file size */
2936     smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2937     smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff);              /* alloc size */
2938     smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2939
2940         /* file attribute */
2941     smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2942         
2943     /* and finalize stuff */
2944     smb_SetSMBDataLength(outp, 0);
2945     code = 0;
2946
2947   done:
2948         lock_ReleaseMutex(&scp->mx);
2949         cm_ReleaseUser(userp);
2950         smb_ReleaseFID(fidp);
2951         return code;
2952 }
2953
2954 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2955 {
2956         unsigned short fid;
2957     smb_fid_t *fidp;
2958     cm_scache_t *scp;
2959     long code = 0;
2960         long searchTime;
2961     long unixTime;
2962     cm_user_t *userp;
2963     cm_attr_t attrs;
2964         cm_req_t req;
2965
2966         cm_InitReq(&req);
2967
2968     fid = smb_GetSMBParm(inp, 0);
2969     fid = smb_ChainFID(fid, inp);
2970         
2971     fidp = smb_FindFID(vcp, fid, 0);
2972     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2973                 return CM_ERROR_BADFD;
2974     }
2975         
2976     userp = smb_GetUser(vcp, inp);
2977         
2978     scp = fidp->scp;
2979         
2980         /* now prepare to call cm_setattr.  This message only sets various times,
2981      * and AFS only implements mtime, and we'll set the mtime if that's
2982      * requested.  The others we'll ignore.
2983      */
2984         searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
2985         
2986     if (searchTime != 0) {
2987                 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
2988
2989         if ( unixTime != -1 ) {
2990             attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
2991             attrs.clientModTime = unixTime;
2992             code = cm_SetAttr(scp, &attrs, userp, &req);
2993
2994             osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
2995         } else {
2996             osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
2997         }
2998     }
2999     else code = 0;
3000
3001         cm_ReleaseUser(userp);
3002         smb_ReleaseFID(fidp);
3003         return code;
3004 }
3005
3006
3007 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3008 {
3009         osi_hyper_t offset;
3010     long count, finalCount;
3011     unsigned short fd;
3012     smb_fid_t *fidp;
3013     long code = 0;
3014     cm_user_t *userp;
3015     char *op;
3016         
3017     fd = smb_GetSMBParm(inp, 2);
3018     count = smb_GetSMBParm(inp, 5);
3019     offset.HighPart = 0;        /* too bad */
3020     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
3021
3022     osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
3023              fd, offset.LowPart, count);
3024         
3025         fd = smb_ChainFID(fd, inp);
3026     fidp = smb_FindFID(vcp, fd, 0);
3027     if (!fidp) {
3028                 return CM_ERROR_BADFD;
3029     }
3030         /* set inp->fid so that later read calls in same msg can find fid */
3031     inp->fid = fd;
3032
3033     if (fidp->flags & SMB_FID_IOCTL) {
3034                 return smb_IoctlV3Read(fidp, vcp, inp, outp);
3035     }
3036         
3037         userp = smb_GetUser(vcp, inp);
3038
3039         /* 0 and 1 are reserved for request chaining, were setup by our caller,
3040      * and will be further filled in after we return.
3041      */
3042     smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
3043     smb_SetSMBParm(outp, 3, 0); /* resvd */
3044     smb_SetSMBParm(outp, 4, 0); /* resvd */
3045         smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
3046     /* fill in #6 when we have all the parameters' space reserved */
3047     smb_SetSMBParm(outp, 7, 0); /* resv'd */
3048     smb_SetSMBParm(outp, 8, 0); /* resv'd */
3049     smb_SetSMBParm(outp, 9, 0); /* resv'd */
3050     smb_SetSMBParm(outp, 10, 0);        /* resv'd */
3051         smb_SetSMBParm(outp, 11, 0);    /* reserved */
3052
3053         /* get op ptr after putting in the parms, since otherwise we don't
3054      * know where the data really is.
3055      */
3056     op = smb_GetSMBData(outp, NULL);
3057         
3058     /* now fill in offset from start of SMB header to first data byte (to op) */
3059     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
3060
3061         /* set the packet data length the count of the # of bytes */
3062     smb_SetSMBDataLength(outp, count);
3063
3064 #ifndef DJGPP
3065         code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
3066 #else /* DJGPP */
3067         code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
3068 #endif /* !DJGPP */
3069
3070         /* fix some things up */
3071         smb_SetSMBParm(outp, 5, finalCount);
3072         smb_SetSMBDataLength(outp, finalCount);
3073
3074     smb_ReleaseFID(fidp);
3075
3076     cm_ReleaseUser(userp);
3077     return code;
3078 }   
3079         
3080 /*
3081  * Values for createDisp, copied from NTDDK.H
3082  *
3083  *  FILE_SUPERSEDE      0       (???)
3084  *  FILE_OPEN           1       (open)
3085  *  FILE_CREATE         2       (exclusive)
3086  *  FILE_OPEN_IF        3       (non-exclusive)
3087  *  FILE_OVERWRITE      4       (open & truncate, but do not create)
3088  *  FILE_OVERWRITE_IF   5       (open & truncate, or create)
3089  */
3090
3091 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3092 {
3093         char *pathp, *realPathp;
3094         long code = 0;
3095         cm_space_t *spacep;
3096         cm_user_t *userp;
3097         cm_scache_t *dscp;              /* parent dir */
3098         cm_scache_t *scp;               /* file to create or open */
3099         cm_attr_t setAttr;
3100         char *lastNamep;
3101     char *treeStartp;
3102         unsigned short nameLength;
3103         unsigned int flags;
3104         unsigned int requestOpLock;
3105         unsigned int requestBatchOpLock;
3106         unsigned int mustBeDir;
3107     unsigned int treeCreate;
3108         int realDirFlag;
3109         unsigned int desiredAccess;
3110         unsigned int extAttributes;
3111         unsigned int createDisp;
3112         unsigned int createOptions;
3113         int initialModeBits;
3114         unsigned short baseFid;
3115         smb_fid_t *baseFidp;
3116         smb_fid_t *fidp;
3117         cm_scache_t *baseDirp;
3118         unsigned short openAction;
3119         int parmSlot;
3120         long fidflags;
3121         FILETIME ft;
3122         LARGE_INTEGER sz;
3123         char *tidPathp;
3124         BOOL foundscp;
3125         cm_req_t req;
3126
3127         cm_InitReq(&req);
3128
3129     treeCreate = FALSE;
3130         foundscp = FALSE;
3131         scp = NULL;
3132
3133         nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3134         flags = smb_GetSMBOffsetParm(inp, 3, 1)
3135                   | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3136         requestOpLock = flags & 0x02;
3137         requestBatchOpLock = flags & 0x04;
3138         mustBeDir = flags & 0x08;
3139
3140         /*
3141          * Why all of a sudden 32-bit FID?
3142          * We will reject all bits higher than 16.
3143          */
3144         if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3145                 return CM_ERROR_INVAL;
3146         baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3147         desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3148                           | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3149         extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3150                           | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3151         createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3152                         | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3153         createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3154                           | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3155
3156         /* mustBeDir is never set; createOptions directory bit seems to be
3157          * more important
3158          */
3159         if (createOptions & 1)
3160                 realDirFlag = 1;
3161         else if (createOptions & 0x40)
3162                 realDirFlag = 0;
3163         else
3164                 realDirFlag = -1;
3165
3166         /*
3167          * compute initial mode bits based on read-only flag in
3168          * extended attributes
3169          */
3170         initialModeBits = 0666;
3171         if (extAttributes & 1) initialModeBits &= ~0222;
3172
3173         pathp = smb_GetSMBData(inp, NULL);
3174         /* Sometimes path is not null-terminated, so we make a copy. */
3175         realPathp = malloc(nameLength+1);
3176         memcpy(realPathp, pathp, nameLength);
3177         realPathp[nameLength] = 0;
3178
3179         spacep = inp->spacep;
3180         smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3181
3182     osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
3183     osi_Log4(smb_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
3184
3185         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3186                 /* special case magic file name for receiving IOCTL requests
3187                  * (since IOCTL calls themselves aren't getting through).
3188                  */
3189                 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3190                 smb_SetupIoctlFid(fidp, spacep);
3191
3192                 /* set inp->fid so that later read calls in same msg can find fid */
3193                 inp->fid = fidp->fid;
3194
3195                 /* out parms */
3196                 parmSlot = 2;
3197                 smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
3198                 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3199                 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3200                 /* times */
3201                 memset(&ft, 0, sizeof(ft));
3202                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3203                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3204                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3205                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3206                 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3207                 sz.HighPart = 0x7fff; sz.LowPart = 0;
3208                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3209                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3210                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
3211                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
3212                 smb_SetSMBParmByte(outp, parmSlot, 0);  /* is a dir? */
3213                 smb_SetSMBDataLength(outp, 0);
3214
3215                 /* clean up fid reference */
3216                 smb_ReleaseFID(fidp);
3217                 free(realPathp);
3218                 return 0;
3219         }
3220
3221 #ifdef DEBUG_VERBOSE
3222     {
3223         char *hexp, *asciip;
3224         asciip = (lastNamep? lastNamep : realPathp);
3225         hexp = osi_HexifyString( asciip );
3226         DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
3227         free(hexp);
3228     }
3229 #endif
3230     userp = smb_GetUser(vcp, inp);
3231     if (!userp) {
3232         osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
3233         free(realPathp);
3234         return CM_ERROR_INVAL;
3235     }
3236
3237         if (baseFid == 0) {
3238                 baseDirp = cm_rootSCachep;
3239                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3240         }
3241         else {
3242         baseFidp = smb_FindFID(vcp, baseFid, 0);
3243         if (!baseFidp) {
3244                 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
3245                 free(realPathp);
3246                 cm_ReleaseUser(userp);
3247                 return CM_ERROR_INVAL;
3248         }
3249                 baseDirp = baseFidp->scp;
3250                 tidPathp = NULL;
3251         }
3252
3253     osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
3254         
3255     /* compute open mode */
3256         fidflags = 0;
3257         if (desiredAccess & DELETE)
3258                 fidflags |= SMB_FID_OPENDELETE;
3259         if (desiredAccess & AFS_ACCESS_READ)
3260                 fidflags |= SMB_FID_OPENREAD;
3261         if (desiredAccess & AFS_ACCESS_WRITE)
3262                 fidflags |= SMB_FID_OPENWRITE;
3263
3264         dscp = NULL;
3265         code = 0;
3266         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3267                         userp, tidPathp, &req, &scp);
3268         if (code == 0) foundscp = TRUE;
3269         if (code != 0
3270             || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3271                 /* look up parent directory */
3272         /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
3273         the immediate parent.  We have to work our way up realPathp until we hit something that we
3274         recognize.
3275         */
3276
3277         while(1) {
3278             char *tp;
3279
3280             code = cm_NameI(baseDirp, spacep->data,
3281                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3282                              userp, tidPathp, &req, &dscp);
3283
3284             if (code && 
3285                 (tp = strrchr(spacep->data,'\\')) &&
3286                 (createDisp == 2) &&
3287                 (realDirFlag == 1)) {
3288                 *tp++ = 0;
3289                 treeCreate = TRUE;
3290                 treeStartp = realPathp + (tp - spacep->data);
3291
3292                 if (*tp && !smb_IsLegalFilename(tp)) {
3293                     if(baseFid != 0) smb_ReleaseFID(baseFidp);
3294                     cm_ReleaseUser(userp);
3295                     free(realPathp);
3296                     return CM_ERROR_BADNTFILENAME;
3297                 }
3298             }
3299             else
3300                 break;
3301         }
3302
3303         if (baseFid != 0) smb_ReleaseFID(baseFidp);
3304
3305         if (code) {
3306             osi_Log0(smb_logp,"NTCreateX parent not found");
3307             cm_ReleaseUser(userp);
3308             free(realPathp);
3309             return code;
3310         }
3311
3312         if(treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
3313             /* A file exists where we want a directory. */
3314             cm_ReleaseSCache(dscp);
3315             cm_ReleaseUser(userp);
3316             free(realPathp);
3317             return CM_ERROR_EXISTS;
3318         }
3319
3320         if (!lastNamep) lastNamep = realPathp;
3321         else lastNamep++;
3322
3323         if (!smb_IsLegalFilename(lastNamep)) {
3324             cm_ReleaseSCache(dscp);
3325             cm_ReleaseUser(userp);
3326             free(realPathp);
3327             return CM_ERROR_BADNTFILENAME;
3328         }
3329
3330         if (!foundscp && !treeCreate) {
3331                         code = cm_Lookup(dscp, lastNamep,
3332                                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3333                                          userp, &req, &scp);
3334                         if (code && code != CM_ERROR_NOSUCHFILE) {
3335                                 cm_ReleaseSCache(dscp);
3336                                 cm_ReleaseUser(userp);
3337                                 free(realPathp);
3338                                 return code;
3339                         }
3340                 }
3341         }
3342         else {
3343                 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3344         }
3345
3346         /* if we get here, if code is 0, the file exists and is represented by
3347          * scp.  Otherwise, we have to create it.  The dir may be represented
3348          * by dscp, or we may have found the file directly.  If code is non-zero,
3349          * scp is NULL.
3350          */
3351         if (code == 0 && !treeCreate) {
3352                 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3353                                       &req);
3354                 if (code) {
3355                         if (dscp) cm_ReleaseSCache(dscp);
3356                         cm_ReleaseSCache(scp);
3357                         cm_ReleaseUser(userp);
3358                         free(realPathp);
3359                         return code;
3360                 }
3361
3362                 if (createDisp == 2) {
3363                         /* oops, file shouldn't be there */
3364                         if (dscp) cm_ReleaseSCache(dscp);
3365                         cm_ReleaseSCache(scp);
3366                         cm_ReleaseUser(userp);
3367                         free(realPathp);
3368                         return CM_ERROR_EXISTS;
3369                 }
3370
3371                 if (createDisp == 4
3372                     || createDisp == 5) {
3373                         setAttr.mask = CM_ATTRMASK_LENGTH;
3374                         setAttr.length.LowPart = 0;
3375                         setAttr.length.HighPart = 0;
3376                         code = cm_SetAttr(scp, &setAttr, userp, &req);
3377                         openAction = 3; /* truncated existing file */
3378                 }
3379                 else openAction = 1;    /* found existing file */
3380         }
3381         else if (createDisp == 1 || createDisp == 4) {
3382                 /* don't create if not found */
3383                 if (dscp) cm_ReleaseSCache(dscp);
3384                 cm_ReleaseUser(userp);
3385                 free(realPathp);
3386                 return CM_ERROR_NOSUCHFILE;
3387         }
3388         else if (realDirFlag == 0 || realDirFlag == -1) {
3389                 osi_assert(dscp != NULL);
3390                 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
3391                                 osi_LogSaveString(smb_logp, lastNamep));
3392                 openAction = 2;         /* created file */
3393                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3394                 setAttr.clientModTime = time(NULL);
3395                 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3396                                  &req);
3397                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3398                         smb_NotifyChange(FILE_ACTION_ADDED,
3399                                          FILE_NOTIFY_CHANGE_FILE_NAME,
3400                                          dscp, lastNamep, NULL, TRUE);
3401                 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3402                         /* Not an exclusive create, and someone else tried
3403                          * creating it already, then we open it anyway.  We
3404                          * don't bother retrying after this, since if this next
3405                          * fails, that means that the file was deleted after we
3406                          * started this call.
3407                          */
3408                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3409                                          userp, &req, &scp);
3410                         if (code == 0) {
3411                                 if (createDisp == 5) {
3412                                         setAttr.mask = CM_ATTRMASK_LENGTH;
3413                                         setAttr.length.LowPart = 0;
3414                                         setAttr.length.HighPart = 0;
3415                                         code = cm_SetAttr(scp, &setAttr, userp,
3416                                                           &req);
3417                                 }
3418                         }       /* lookup succeeded */
3419                 }
3420         }
3421         else {
3422         char *tp, *pp;
3423         char *cp; /* This component */
3424         int clen = 0; /* length of component */
3425         cm_scache_t *tscp;
3426         int isLast = 0;
3427                 
3428         /* create directory */
3429                 if ( !treeCreate ) treeStartp = lastNamep;
3430         osi_assert(dscp != NULL);
3431         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
3432                                 osi_LogSaveString(smb_logp, treeStartp));
3433                 openAction = 2;         /* created directory */
3434
3435                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3436                 setAttr.clientModTime = time(NULL);
3437                 
3438                 pp = treeStartp;
3439                 cp = spacep->data;
3440                 tscp = dscp;
3441
3442                 while(pp && *pp) {
3443                         tp = strchr(pp, '\\');
3444                         if(!tp) {
3445                                 strcpy(cp,pp);
3446                 clen = strlen(cp);
3447                                 isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
3448                         }
3449                         else {
3450                                 clen = tp - pp;
3451                                 strncpy(cp,pp,clen);
3452                                 *(cp + clen) = 0;
3453                                 tp++;
3454                         }
3455                         pp = tp;
3456
3457                         if(clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
3458
3459                         /* cp is the next component to be created. */
3460                         code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
3461                         if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
3462                                 smb_NotifyChange(FILE_ACTION_ADDED,
3463                                 FILE_NOTIFY_CHANGE_DIR_NAME,
3464                                 tscp, cp, NULL, TRUE);
3465                         if (code == 0 || 
3466                                 (code == CM_ERROR_EXISTS && createDisp != 2)) {
3467                                         /* Not an exclusive create, and someone else tried
3468                                         * creating it already, then we open it anyway.  We
3469                                         * don't bother retrying after this, since if this next
3470                                         * fails, that means that the file was deleted after we
3471                                         * started this call.
3472                                         */
3473                                         code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
3474                                                 userp, &req, &scp);
3475                                 }
3476                         if(code) break;
3477
3478                         if(!isLast) { /* for anything other than dscp, release it unless it's the last one */
3479                                 cm_ReleaseSCache(tscp);
3480                                 tscp = scp; /* Newly created directory will be next parent */
3481                         }
3482                 }
3483
3484                 /* 
3485                 if we get here and code == 0, then scp is the last directory created, and tscp is the
3486                 parent of scp.  dscp got released if dscp != tscp. both tscp and scp are held.
3487                 */
3488                 dscp = tscp;
3489         }
3490
3491         if (code) {
3492                 /* something went wrong creating or truncating the file */
3493                 if (scp) cm_ReleaseSCache(scp);
3494         if (dscp) cm_ReleaseSCache(dscp);
3495                 cm_ReleaseUser(userp);
3496                 free(realPathp);
3497                 return code;
3498         }
3499
3500         /* make sure we have file vs. dir right (only applies for single component case) */
3501         if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3502                 cm_ReleaseSCache(scp);
3503         if (dscp) cm_ReleaseSCache(dscp);
3504                 cm_ReleaseUser(userp);
3505                 free(realPathp);
3506                 return CM_ERROR_ISDIR;
3507         }
3508     /* (only applies to single component case) */
3509         if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3510                 cm_ReleaseSCache(scp);
3511         if (dscp) cm_ReleaseSCache(dscp);
3512                 cm_ReleaseUser(userp);
3513                 free(realPathp);
3514                 return CM_ERROR_NOTDIR;
3515         }
3516
3517         /* open the file itself */
3518         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3519         osi_assert(fidp);
3520         /* save a pointer to the vnode */
3521         fidp->scp = scp;
3522
3523         fidp->flags = fidflags;
3524
3525         /* save parent dir and pathname for delete or change notification */
3526         if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3527                 fidp->flags |= SMB_FID_NTOPEN;
3528                 fidp->NTopen_dscp = dscp;
3529                 cm_HoldSCache(dscp);
3530                 fidp->NTopen_pathp = strdup(lastNamep);
3531         }
3532         fidp->NTopen_wholepathp = realPathp;
3533
3534         /* we don't need this any longer */
3535         if (dscp) cm_ReleaseSCache(dscp);
3536         cm_Open(scp, 0, userp);
3537
3538         /* set inp->fid so that later read calls in same msg can find fid */
3539         inp->fid = fidp->fid;
3540
3541         /* out parms */
3542         parmSlot = 2;
3543         lock_ObtainMutex(&scp->mx);
3544         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
3545         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3546         smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3547         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3548         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3549         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3550         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3551         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3552         smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3553                                                 parmSlot += 2;
3554         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3555         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3556         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
3557         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
3558         smb_SetSMBParmByte(outp, parmSlot,
3559                 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3560         lock_ReleaseMutex(&scp->mx);
3561         smb_SetSMBDataLength(outp, 0);
3562
3563         osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3564                  osi_LogSaveString(smb_logp, realPathp));
3565
3566         smb_ReleaseFID(fidp);
3567
3568         cm_ReleaseUser(userp);
3569
3570     /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
3571
3572         /* leave scp held since we put it in fidp->scp */
3573         return 0;
3574 }
3575
3576 /*
3577  * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3578  * Instead, ultimately, would like to use a subroutine for common code.
3579  */
3580 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3581 {
3582         char *pathp, *realPathp;
3583         long code = 0;
3584         cm_space_t *spacep;
3585         cm_user_t *userp;
3586         cm_scache_t *dscp;              /* parent dir */
3587         cm_scache_t *scp;               /* file to create or open */
3588         cm_attr_t setAttr;
3589         char *lastNamep;
3590         unsigned long nameLength;
3591         unsigned int flags;
3592         unsigned int requestOpLock;
3593         unsigned int requestBatchOpLock;
3594         unsigned int mustBeDir;
3595     unsigned int extendedRespRequired;
3596         int realDirFlag;
3597         unsigned int desiredAccess;
3598 #ifdef DEBUG_VERBOSE    
3599     unsigned int allocSize;
3600     unsigned int shareAccess;
3601 #endif
3602         unsigned int extAttributes;
3603         unsigned int createDisp;
3604 #ifdef DEBUG_VERBOSE
3605     unsigned int sdLen;
3606 #endif
3607         unsigned int createOptions;
3608         int initialModeBits;
3609         unsigned short baseFid;
3610         smb_fid_t *baseFidp;
3611         smb_fid_t *fidp;
3612         cm_scache_t *baseDirp;
3613         unsigned short openAction;
3614         int parmSlot;
3615         long fidflags;
3616         FILETIME ft;
3617         char *tidPathp;
3618         BOOL foundscp;
3619         int parmOffset, dataOffset;
3620         char *parmp;
3621         ULONG *lparmp;
3622         char *outData;
3623         cm_req_t req;
3624
3625         cm_InitReq(&req);
3626
3627         foundscp = FALSE;
3628         scp = NULL;
3629
3630         parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3631                         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3632         parmp = inp->data + parmOffset;
3633         lparmp = (ULONG *) parmp;
3634
3635         flags = lparmp[0];
3636         requestOpLock = flags & 0x02;
3637         requestBatchOpLock = flags & 0x04;
3638         mustBeDir = flags & 0x08;
3639     extendedRespRequired = flags & 0x10;
3640
3641         /*
3642          * Why all of a sudden 32-bit FID?
3643          * We will reject all bits higher than 16.
3644          */
3645         if (lparmp[1] & 0xFFFF0000)
3646                 return CM_ERROR_INVAL;
3647         baseFid = (unsigned short)lparmp[1];
3648         desiredAccess = lparmp[2];
3649 #ifdef DEBUG_VERBOSE
3650     allocSize = lparmp[3];
3651 #endif /* DEBUG_VERSOSE */
3652         extAttributes = lparmp[5];
3653 #ifdef DEBUG_VEROSE
3654     shareAccess = lparmp[6];
3655 #endif
3656         createDisp = lparmp[7];
3657         createOptions = lparmp[8];
3658 #ifdef DEBUG_VERBOSE
3659     sdLen = lparmp[9];
3660 #endif
3661         nameLength = lparmp[11];
3662
3663 #ifdef DEBUG_VERBOSE
3664         osi_Log4(smb_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
3665         osi_Log2(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
3666         osi_Log1(smb_logp,"... flags[%x]",flags);
3667 #endif
3668
3669         /* mustBeDir is never set; createOptions directory bit seems to be
3670          * more important
3671          */
3672         if (createOptions & 1)
3673                 realDirFlag = 1;
3674         else if (createOptions & 0x40)
3675                 realDirFlag = 0;
3676         else
3677                 realDirFlag = -1;
3678
3679         /*
3680          * compute initial mode bits based on read-only flag in
3681          * extended attributes
3682          */
3683         initialModeBits = 0666;
3684         if (extAttributes & 1) initialModeBits &= ~0222;
3685
3686         pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3687         /* Sometimes path is not null-terminated, so we make a copy. */
3688         realPathp = malloc(nameLength+1);
3689         memcpy(realPathp, pathp, nameLength);
3690         realPathp[nameLength] = 0;
3691
3692         spacep = cm_GetSpace();
3693         smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3694
3695         /*
3696          * Nothing here to handle SMB_IOCTL_FILENAME.
3697          * Will add it if necessary.
3698          */
3699
3700 #ifdef DEBUG_VERBOSE
3701         {
3702                 char *hexp, *asciip;
3703                 asciip = (lastNamep? lastNamep : realPathp);
3704                 hexp = osi_HexifyString( asciip );
3705                 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
3706                 free(hexp);
3707         }
3708 #endif
3709
3710         userp = smb_GetUser(vcp, inp);
3711     if(!userp) {
3712         osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
3713         free(realPathp);
3714         return CM_ERROR_INVAL;
3715     }
3716
3717         if (baseFid == 0) {
3718                 baseDirp = cm_rootSCachep;
3719                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3720         }
3721         else {
3722         baseFidp = smb_FindFID(vcp, baseFid, 0);
3723         if(!baseFidp) {
3724                 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
3725                 free(realPathp);
3726                 cm_ReleaseUser(userp);
3727                 return CM_ERROR_INVAL;
3728         }
3729                 baseDirp = baseFidp->scp;
3730                 tidPathp = NULL;
3731         }
3732
3733     /* compute open mode */
3734     fidflags = 0;
3735     if (desiredAccess & DELETE)
3736         fidflags |= SMB_FID_OPENDELETE;
3737     if (desiredAccess & AFS_ACCESS_READ)
3738         fidflags |= SMB_FID_OPENREAD;
3739     if (desiredAccess & AFS_ACCESS_WRITE)
3740         fidflags |= SMB_FID_OPENWRITE;
3741
3742         dscp = NULL;
3743         code = 0;
3744         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3745                         userp, tidPathp, &req, &scp);
3746         if (code == 0) foundscp = TRUE;
3747         if (code != 0
3748             || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3749                 /* look up parent directory */
3750                 code = cm_NameI(baseDirp, spacep->data,
3751                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3752                                 userp, tidPathp, &req, &dscp);
3753                 cm_FreeSpace(spacep);
3754
3755                 if (baseFid != 0) {
3756            smb_ReleaseFID(baseFidp);
3757            baseFidp = 0;
3758         }
3759
3760                 if (code) {
3761                         cm_ReleaseUser(userp);
3762                         free(realPathp);
3763                         return code;
3764                 }
3765
3766                 if (!lastNamep) lastNamep = realPathp;
3767                 else lastNamep++;
3768
3769         if (!smb_IsLegalFilename(lastNamep))
3770             return CM_ERROR_BADNTFILENAME;
3771
3772                 if (!foundscp) {
3773                         code = cm_Lookup(dscp, lastNamep,
3774                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3775                              userp, &req, &scp);
3776                         if (code && code != CM_ERROR_NOSUCHFILE) {
3777                                 cm_ReleaseSCache(dscp);
3778                                 cm_ReleaseUser(userp);
3779                                 free(realPathp);
3780                                 return code;
3781                         }
3782                 }
3783         }
3784         else {
3785                 if (baseFid != 0) {
3786             smb_ReleaseFID(baseFidp);
3787             baseFidp = 0;
3788         }
3789                 cm_FreeSpace(spacep);
3790         }
3791
3792         /* if we get here, if code is 0, the file exists and is represented by
3793          * scp.  Otherwise, we have to create it.  The dir may be represented
3794          * by dscp, or we may have found the file directly.  If code is non-zero,
3795          * scp is NULL.
3796          */
3797         if (code == 0) {
3798                 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3799                                       &req);
3800                 if (code) {
3801                         if (dscp) cm_ReleaseSCache(dscp);
3802                         cm_ReleaseSCache(scp);
3803                         cm_ReleaseUser(userp);
3804                         free(realPathp);
3805                         return code;
3806                 }
3807
3808                 if (createDisp == 2) {
3809                         /* oops, file shouldn't be there */
3810                         if (dscp) cm_ReleaseSCache(dscp);
3811                         cm_ReleaseSCache(scp);
3812                         cm_ReleaseUser(userp);
3813                         free(realPathp);
3814                         return CM_ERROR_EXISTS;
3815                 }
3816
3817                 if (createDisp == 4
3818                     || createDisp == 5) {
3819                         setAttr.mask = CM_ATTRMASK_LENGTH;
3820                         setAttr.length.LowPart = 0;
3821                         setAttr.length.HighPart = 0;
3822                         code = cm_SetAttr(scp, &setAttr, userp, &req);
3823                         openAction = 3; /* truncated existing file */
3824                 }
3825                 else openAction = 1;    /* found existing file */
3826         }
3827         else if (createDisp == 1 || createDisp == 4) {
3828                 /* don't create if not found */
3829                 if (dscp) cm_ReleaseSCache(dscp);
3830                 cm_ReleaseUser(userp);
3831                 free(realPathp);
3832                 return CM_ERROR_NOSUCHFILE;
3833         }
3834         else if (realDirFlag == 0 || realDirFlag == -1) {
3835                 osi_assert(dscp != NULL);
3836                 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
3837                  osi_LogSaveString(smb_logp, lastNamep));
3838                 openAction = 2;         /* created file */
3839                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3840                 setAttr.clientModTime = time(NULL);
3841                 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3842                                  &req);
3843                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3844                         smb_NotifyChange(FILE_ACTION_ADDED,
3845                                          FILE_NOTIFY_CHANGE_FILE_NAME,
3846                                          dscp, lastNamep, NULL, TRUE);
3847                 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3848                         /* Not an exclusive create, and someone else tried
3849                          * creating it already, then we open it anyway.  We
3850                          * don't bother retrying after this, since if this next
3851                          * fails, that means that the file was deleted after we
3852                          * started this call.
3853                          */
3854                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3855                                          userp, &req, &scp);
3856                         if (code == 0) {
3857                                 if (createDisp == 5) {
3858                                         setAttr.mask = CM_ATTRMASK_LENGTH;
3859                                         setAttr.length.LowPart = 0;
3860                                         setAttr.length.HighPart = 0;
3861                                         code = cm_SetAttr(scp, &setAttr, userp,
3862                                                           &req);
3863                                 }
3864                         }       /* lookup succeeded */
3865                 }
3866         }
3867         else {
3868                 /* create directory */
3869                 osi_assert(dscp != NULL);
3870                 osi_Log1(smb_logp,
3871                                 "smb_ReceiveNTTranCreate creating directory %s",
3872                                 osi_LogSaveString(smb_logp, lastNamep));
3873                 openAction = 2;         /* created directory */
3874                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3875                 setAttr.clientModTime = time(NULL);
3876                 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3877                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3878                         smb_NotifyChange(FILE_ACTION_ADDED,
3879                                          FILE_NOTIFY_CHANGE_DIR_NAME,
3880                                          dscp, lastNamep, NULL, TRUE);
3881                 if (code == 0
3882                     || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3883                         /* Not an exclusive create, and someone else tried
3884                          * creating it already, then we open it anyway.  We
3885                          * don't bother retrying after this, since if this next
3886                          * fails, that means that the file was deleted after we
3887                          * started this call.
3888                          */
3889                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3890                                          userp, &req, &scp);
3891                 }
3892         }
3893
3894         if (code) {
3895                 /* something went wrong creating or truncating the file */
3896                 if (scp) cm_ReleaseSCache(scp);
3897                 cm_ReleaseUser(userp);
3898                 free(realPathp);
3899                 return code;
3900         }
3901
3902         /* make sure we have file vs. dir right */
3903         if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3904                 cm_ReleaseSCache(scp);
3905                 cm_ReleaseUser(userp);
3906                 free(realPathp);
3907                 return CM_ERROR_ISDIR;
3908         }
3909         if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3910                 cm_ReleaseSCache(scp);
3911                 cm_ReleaseUser(userp);
3912                 free(realPathp);
3913                 return CM_ERROR_NOTDIR;
3914         }
3915
3916         /* open the file itself */
3917         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3918         osi_assert(fidp);
3919
3920         /* save a pointer to the vnode */
3921         fidp->scp = scp;
3922
3923         fidp->flags = fidflags;
3924
3925     /* save parent dir and pathname for deletion or change notification */
3926     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3927         fidp->flags |= SMB_FID_NTOPEN;
3928         fidp->NTopen_dscp = dscp;
3929         cm_HoldSCache(dscp);
3930         fidp->NTopen_pathp = strdup(lastNamep);
3931     }
3932         fidp->NTopen_wholepathp = realPathp;
3933
3934         /* we don't need this any longer */
3935         if (dscp) cm_ReleaseSCache(dscp);
3936
3937         cm_Open(scp, 0, userp);
3938
3939         /* set inp->fid so that later read calls in same msg can find fid */
3940         inp->fid = fidp->fid;
3941
3942     /* check whether we are required to send an extended response */
3943     if (!extendedRespRequired) {
3944         /* out parms */
3945         parmOffset = 8*4 + 39;
3946         parmOffset += 1;        /* pad to 4 */
3947         dataOffset = parmOffset + 70;
3948
3949         parmSlot = 1;
3950         outp->oddByte = 1;
3951         /* Total Parameter Count */
3952         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3953         /* Total Data Count */
3954         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3955         /* Parameter Count */
3956         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3957         /* Parameter Offset */
3958         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3959         /* Parameter Displacement */
3960         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3961         /* Data Count */
3962         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3963         /* Data Offset */
3964         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3965         /* Data Displacement */
3966         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3967         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
3968         smb_SetSMBDataLength(outp, 70);
3969
3970         lock_ObtainMutex(&scp->mx);
3971         outData = smb_GetSMBData(outp, NULL);
3972         outData++;                      /* round to get to parmOffset */
3973         *outData = 0; outData++;        /* oplock */
3974         *outData = 0; outData++;        /* reserved */
3975         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
3976         *((ULONG *)outData) = openAction; outData += 4;
3977         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
3978         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3979         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
3980         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
3981         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
3982         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
3983         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
3984         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
3985         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
3986         *((USHORT *)outData) = 0; outData += 2; /* filetype */
3987         *((USHORT *)outData) = 0; outData += 2; /* dev state */
3988         *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
3989         outData += 2;   /* is a dir? */
3990         lock_ReleaseMutex(&scp->mx);
3991     } else {
3992         /* out parms */
3993         parmOffset = 8*4 + 39;
3994         parmOffset += 1;        /* pad to 4 */
3995         dataOffset = parmOffset + 104;
3996         
3997         parmSlot = 1;
3998         outp->oddByte = 1;
3999         /* Total Parameter Count */
4000         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
4001         /* Total Data Count */
4002         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4003         /* Parameter Count */
4004         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
4005         /* Parameter Offset */
4006         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4007         /* Parameter Displacement */
4008         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4009         /* Data Count */
4010         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4011         /* Data Offset */
4012         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4013         /* Data Displacement */
4014         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4015         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
4016         smb_SetSMBDataLength(outp, 105);
4017         
4018         lock_ObtainMutex(&scp->mx);
4019         outData = smb_GetSMBData(outp, NULL);
4020         outData++;                      /* round to get to parmOffset */
4021         *outData = 0; outData++;        /* oplock */
4022         *outData = 1; outData++;        /* response type */
4023         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
4024         *((ULONG *)outData) = openAction; outData += 4;
4025         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
4026         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4027         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
4028         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
4029         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
4030         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
4031         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
4032         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
4033         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
4034         *((USHORT *)outData) = 0; outData += 2; /* filetype */
4035         *((USHORT *)outData) = 0; outData += 2; /* dev state */
4036         *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
4037         outData += 1;   /* is a dir? */
4038         memset(outData,0,24); outData += 24; /* Volume ID and file ID */
4039         *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
4040         *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
4041         lock_ReleaseMutex(&scp->mx);
4042     }
4043
4044         osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
4045
4046         smb_ReleaseFID(fidp);
4047
4048         cm_ReleaseUser(userp);
4049
4050         /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
4051         /* leave scp held since we put it in fidp->scp */
4052         return 0;
4053 }
4054
4055 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
4056         smb_packet_t *outp)
4057 {
4058         smb_packet_t *savedPacketp;
4059         ULONG filter; USHORT fid, watchtree;
4060         smb_fid_t *fidp;
4061         cm_scache_t *scp;
4062         
4063         filter = smb_GetSMBParm(inp, 19)
4064                         | (smb_GetSMBParm(inp, 20) << 16);
4065         fid = smb_GetSMBParm(inp, 21);
4066         watchtree = smb_GetSMBParm(inp, 22) && 0xffff;  /* TODO: should this be 0xff ? */
4067
4068     fidp = smb_FindFID(vcp, fid, 0);
4069     if (!fidp) {
4070         osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
4071         return CM_ERROR_BADFD;
4072     }
4073
4074         savedPacketp = smb_CopyPacket(inp);
4075         savedPacketp->vcp = vcp; /* TODO: refcount vcp? */
4076         lock_ObtainMutex(&smb_Dir_Watch_Lock);
4077         savedPacketp->nextp = smb_Directory_Watches;
4078         smb_Directory_Watches = savedPacketp;
4079         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4080
4081     osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
4082              filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
4083
4084     scp = fidp->scp;
4085     lock_ObtainMutex(&scp->mx);
4086     if (watchtree)
4087         scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
4088     else
4089         scp->flags |= CM_SCACHEFLAG_WATCHED;
4090     lock_ReleaseMutex(&scp->mx);
4091     smb_ReleaseFID(fidp);
4092
4093         outp->flags |= SMB_PACKETFLAG_NOSEND;
4094         return 0;
4095 }
4096
4097 unsigned char nullSecurityDesc[36] = {
4098         0x01,                           /* security descriptor revision */
4099         0x00,                           /* reserved, should be zero */
4100         0x00, 0x80,                     /* security descriptor control;
4101                                          * 0x8000 : self-relative format */
4102         0x14, 0x00, 0x00, 0x00,         /* offset of owner SID */
4103         0x1c, 0x00, 0x00, 0x00,         /* offset of group SID */
4104         0x00, 0x00, 0x00, 0x00,         /* offset of DACL would go here */
4105         0x00, 0x00, 0x00, 0x00,         /* offset of SACL would go here */
4106         0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4107                                         /* "null SID" owner SID */
4108         0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4109                                         /* "null SID" group SID */
4110 };
4111
4112 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4113 {
4114         int parmOffset, parmCount, dataOffset, dataCount;
4115         int parmSlot;
4116         int maxData;
4117         char *outData;
4118         char *parmp;
4119         USHORT *sparmp;
4120         ULONG *lparmp;
4121         USHORT fid;
4122         ULONG securityInformation;
4123
4124         parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
4125                         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
4126         parmp = inp->data + parmOffset;
4127         sparmp = (USHORT *) parmp;
4128         lparmp = (ULONG *) parmp;
4129
4130         fid = sparmp[0];
4131         securityInformation = lparmp[1];
4132
4133         maxData = smb_GetSMBOffsetParm(inp, 7, 1)
4134                         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4135
4136         if (maxData < 36)
4137                 dataCount = 0;
4138         else
4139                 dataCount = 36;
4140
4141         /* out parms */
4142         parmOffset = 8*4 + 39;
4143         parmOffset += 1;        /* pad to 4 */
4144         parmCount = 4;
4145         dataOffset = parmOffset + parmCount;
4146
4147         parmSlot = 1;
4148         outp->oddByte = 1;
4149         /* Total Parameter Count */
4150         smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
4151         /* Total Data Count */
4152         smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
4153         /* Parameter Count */
4154         smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
4155         /* Parameter Offset */
4156         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4157         /* Parameter Displacement */
4158         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4159         /* Data Count */
4160         smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
4161         /* Data Offset */
4162         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4163         /* Data Displacement */
4164         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4165         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
4166         smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
4167
4168         outData = smb_GetSMBData(outp, NULL);
4169         outData++;                      /* round to get to parmOffset */
4170         *((ULONG *)outData) = 36; outData += 4; /* length */
4171
4172         if (maxData >= 36) {
4173                 memcpy(outData, nullSecurityDesc, 36);
4174                 outData += 36;
4175                 return 0;
4176         } else
4177                 return CM_ERROR_BUFFERTOOSMALL;
4178 }
4179
4180 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4181 {
4182         unsigned short function;
4183
4184         function = smb_GetSMBParm(inp, 18);
4185
4186         osi_Log1(smb_logp, "SMB NT Transact function %d", function);
4187
4188         /* We can handle long names */
4189         if (vcp->flags & SMB_VCFLAG_USENT)
4190                 ((smb_t *)outp)->flg2 |= 0x40;  /* IS_LONG_NAME */
4191         
4192         switch (function) {
4193
4194                 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
4195
4196                 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
4197
4198                 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
4199
4200                 default: return CM_ERROR_INVAL;
4201         }
4202 }
4203
4204 /*
4205  * smb_NotifyChange -- find relevant change notification messages and
4206  *                     reply to them
4207  *
4208  * If we don't know the file name (i.e. a callback break), filename is
4209  * NULL, and we return a zero-length list.
4210  */
4211 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
4212         cm_scache_t *dscp, char *filename, char *otherFilename,
4213         BOOL isDirectParent)
4214 {
4215         smb_packet_t *watch, *lastWatch, *nextWatch;
4216         ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
4217         char *outData, *oldOutData;
4218         ULONG filter;
4219         USHORT fid, wtree;
4220         ULONG maxLen;
4221         BOOL twoEntries = FALSE;
4222         ULONG otherNameLen, oldParmCount = 0;
4223         DWORD otherAction;
4224         smb_vc_t *vcp;
4225         smb_fid_t *fidp;
4226
4227         /* Get ready for rename within directory */
4228         if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
4229                 twoEntries = TRUE;
4230                 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
4231         }
4232
4233         lock_ObtainMutex(&smb_Dir_Watch_Lock);
4234         watch = smb_Directory_Watches;
4235         while (watch) {
4236                 filter = smb_GetSMBParm(watch, 19)
4237                                 | (smb_GetSMBParm(watch, 20) << 16);
4238                 fid = smb_GetSMBParm(watch, 21);
4239                 wtree = smb_GetSMBParm(watch, 22) & 0xffff;  /* TODO: should this be 0xff ? */
4240                 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
4241                                 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
4242                 vcp = watch->vcp;
4243
4244                 /*
4245                  * Strange hack - bug in NT Client and NT Server that we
4246                  * must emulate?
4247                  */
4248                 if (filter == 3 && wtree)
4249                         filter = 0x17;
4250
4251                 fidp = smb_FindFID(vcp, fid, 0);
4252         if (!fidp) {
4253                 lastWatch = watch;
4254                 watch = watch->nextp;
4255                 continue;
4256         }
4257                 if (fidp->scp != dscp
4258                     || (filter & notifyFilter) == 0
4259                     || (!isDirectParent && !wtree)) {
4260                         smb_ReleaseFID(fidp);
4261                         lastWatch = watch;
4262                         watch = watch->nextp;
4263                         continue;
4264                 }
4265                 smb_ReleaseFID(fidp);
4266
4267                 osi_Log4(smb_logp,
4268                          "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
4269                          fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
4270
4271                 nextWatch = watch->nextp;
4272                 if (watch == smb_Directory_Watches)
4273                         smb_Directory_Watches = nextWatch;
4274                 else
4275                         lastWatch->nextp = nextWatch;
4276
4277                 /* Turn off WATCHED flag in dscp */
4278                 lock_ObtainMutex(&dscp->mx);
4279                 if (wtree)
4280                         dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4281                 else
4282                         dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
4283                 lock_ReleaseMutex(&dscp->mx);
4284
4285                 /* Convert to response packet */
4286                 ((smb_t *) watch)->reb = 0x80;
4287                 ((smb_t *) watch)->wct = 0;
4288
4289                 /* out parms */
4290                 if (filename == NULL)
4291                         parmCount = 0;
4292                 else {
4293                         nameLen = strlen(filename);
4294                         parmCount = 3*4 + nameLen*2;
4295                         parmCount = (parmCount + 3) & ~3;       /* pad to 4 */
4296                         if (twoEntries) {
4297                                 otherNameLen = strlen(otherFilename);
4298                                 oldParmCount = parmCount;
4299                                 parmCount += 3*4 + otherNameLen*2;
4300                                 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
4301                         }
4302                         if (maxLen < parmCount)
4303                                 parmCount = 0;  /* not enough room */
4304                 }
4305                 parmOffset = 8*4 + 39;
4306                 parmOffset += 1;                        /* pad to 4 */
4307                 dataOffset = parmOffset + parmCount;
4308
4309                 parmSlot = 1;
4310                 watch->oddByte = 1;
4311                 /* Total Parameter Count */
4312                 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4313                 /* Total Data Count */
4314                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4315                 /* Parameter Count */
4316                 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4317                 /* Parameter Offset */
4318                 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
4319                 /* Parameter Displacement */
4320                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4321                 /* Data Count */
4322                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4323                 /* Data Offset */
4324                 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
4325                 /* Data Displacement */
4326                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4327                 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
4328                 smb_SetSMBDataLength(watch, parmCount + 1);
4329
4330                 if (parmCount != 0) {
4331                         outData = smb_GetSMBData(watch, NULL);
4332                         outData++;      /* round to get to parmOffset */
4333                         oldOutData = outData;
4334                         *((DWORD *)outData) = oldParmCount; outData += 4;
4335                                         /* Next Entry Offset */
4336                         *((DWORD *)outData) = action; outData += 4;
4337                                         /* Action */
4338                         *((DWORD *)outData) = nameLen*2; outData += 4;
4339                                         /* File Name Length */
4340                         mbstowcs((WCHAR *)outData, filename, nameLen);
4341                                         /* File Name */
4342                         if (twoEntries) {
4343                                 outData = oldOutData + oldParmCount;
4344                                 *((DWORD *)outData) = 0; outData += 4;
4345                                         /* Next Entry Offset */
4346                                 *((DWORD *)outData) = otherAction; outData += 4;
4347                                         /* Action */
4348                                 *((DWORD *)outData) = otherNameLen*2;
4349                                 outData += 4;   /* File Name Length */
4350                                 mbstowcs((WCHAR *)outData, otherFilename,
4351                                          otherNameLen); /* File Name */
4352                         }
4353                 }
4354
4355                 /*
4356                  * If filename is null, we don't know the cause of the
4357                  * change notification.  We return zero data (see above),
4358                  * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
4359                  * (= 0x010C).  We set the error code here by hand, without
4360                  * modifying wct and bcc.
4361                  */
4362                 if (filename == NULL) {
4363                         ((smb_t *) watch)->rcls = 0x0C;
4364                         ((smb_t *) watch)->reh = 0x01;
4365                         ((smb_t *) watch)->errLow = 0;
4366                         ((smb_t *) watch)->errHigh = 0;
4367                         /* Set NT Status codes flag */
4368                         ((smb_t *) watch)->flg2 |= 0x4000;
4369                 }
4370
4371                 smb_SendPacket(vcp, watch);
4372                 smb_FreePacket(watch);
4373                 watch = nextWatch;
4374         }
4375         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4376 }
4377
4378 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4379 {
4380         unsigned char *replyWctp;
4381         smb_packet_t *watch, *lastWatch;
4382         USHORT fid, watchtree;
4383         smb_fid_t *fidp;
4384         cm_scache_t *scp;
4385
4386         osi_Log0(smb_logp, "SMB3 receive NT cancel");
4387
4388         lock_ObtainMutex(&smb_Dir_Watch_Lock);
4389         watch = smb_Directory_Watches;
4390         while (watch) {
4391                 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
4392                     && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
4393                     && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
4394                     && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
4395                         if (watch == smb_Directory_Watches)
4396                                 smb_Directory_Watches = watch->nextp;
4397                         else
4398                                 lastWatch->nextp = watch->nextp;
4399                         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4400
4401                         /* Turn off WATCHED flag in scp */
4402                         fid = smb_GetSMBParm(watch, 21);
4403                         watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
4404
4405                         fidp = smb_FindFID(vcp, fid, 0);
4406             if (fidp) {
4407                 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s", 
4408                          fid, watchtree,
4409                          osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
4410
4411                 scp = fidp->scp;
4412                 lock_ObtainMutex(&scp->mx);
4413                 if (watchtree)
4414                     scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4415                 else
4416                     scp->flags &= ~CM_SCACHEFLAG_WATCHED;
4417                 lock_ReleaseMutex(&scp->mx);
4418                 smb_ReleaseFID(fidp);
4419             } else {
4420                 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
4421             }
4422
4423                         /* assume STATUS32; return 0xC0000120 (CANCELED) */
4424                         replyWctp = watch->wctp;
4425                         *replyWctp++ = 0;
4426                         *replyWctp++ = 0;
4427                         *replyWctp++ = 0;
4428                         ((smb_t *)watch)->rcls = 0x20;
4429                         ((smb_t *)watch)->reh = 0x1;
4430                         ((smb_t *)watch)->errLow = 0;
4431                         ((smb_t *)watch)->errHigh = 0xC0;
4432                         ((smb_t *)watch)->flg2 |= 0x4000;
4433                         smb_SendPacket(vcp, watch);
4434                         smb_FreePacket(watch);
4435                         return 0;
4436                 }
4437                 lastWatch = watch;
4438                 watch = watch->nextp;
4439         }
4440         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4441
4442         return 0;
4443 }
4444
4445 void smb3_Init()
4446 {
4447         lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
4448 }
4449
4450 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
4451 {
4452     /*int newUid;*/
4453     smb_username_t *unp;
4454
4455     unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
4456     if (!unp->userp) {
4457         lock_ObtainMutex(&unp->mx);
4458         unp->userp = cm_NewUser();
4459         lock_ReleaseMutex(&unp->mx);
4460                 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
4461     }  else     {
4462                 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);
4463         }
4464     return unp->userp;
4465 }
4466