smb-8dot3-pattern-matching-20040401
[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 == '*') return 1;
96         return 0;
97 }
98
99 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
100 {
101         if (chainpp) {
102                 /* skip over null-terminated string */
103                 *chainpp = inp + strlen(inp) + 1;
104         }
105         return inp;
106 }
107
108 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
109 {
110     char *tp;
111     char *usern, *pwd, *pwdx;
112     smb_user_t *uidp;
113     unsigned short newUid;
114     unsigned long caps;
115     cm_user_t *userp;
116     smb_username_t *unp;
117     char *s1 = " ";
118
119     /* Check for bad conns */
120     if (vcp->flags & SMB_VCFLAG_REMOTECONN)
121         return CM_ERROR_REMOTECONN;
122
123     /* For NT LM 0.12 and up, get capabilities */
124     if (vcp->flags & SMB_VCFLAG_USENT) {
125         caps = smb_GetSMBParm(inp, 11);
126         if (caps & 0x40)
127             vcp->flags |= SMB_VCFLAG_STATUS32;
128         /* for now, ignore other capability bits */
129     }
130
131     /* Parse the data */
132     tp = smb_GetSMBData(inp, NULL);
133     if (vcp->flags & SMB_VCFLAG_USENT)
134         pwdx = smb_ParseString(tp, &tp);
135     pwd = smb_ParseString(tp, &tp);
136     usern = smb_ParseString(tp, &tp);
137
138     /* On Windows 2000, this function appears to be called more often than
139        it is expected to be called. This resulted in multiple smb_user_t
140        records existing all for the same user session which results in all
141        of the users tokens disappearing.
142
143        To avoid this problem, we look for an existing smb_user_t record
144        based on the users name, and use that one if we find it.
145     */
146
147     uidp = smb_FindUserByNameThisSession(vcp, usern);
148     if (uidp) {   /* already there, so don't create a new one */
149         unp = uidp->unp;
150         userp = unp->userp;
151         newUid = (unsigned short)uidp->userID;  /* For some reason these are different types!*/
152                 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,usern);
153                 osi_Log3(afsd_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
154         smb_ReleaseUID(uidp);
155     }
156     else {
157       /* do a global search for the username/machine name pair */
158         unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
159
160         /* Create a new UID and cm_user_t structure */
161         userp = unp->userp;
162         if (!userp)
163           userp = cm_NewUser();
164         lock_ObtainMutex(&vcp->mx);
165         if (!vcp->uidCounter)
166             vcp->uidCounter++; /* handle unlikely wraparounds */
167         newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
168         lock_ReleaseMutex(&vcp->mx);
169
170         /* Create a new smb_user_t structure and connect them up */
171         lock_ObtainMutex(&unp->mx);
172         unp->userp = userp;
173         lock_ReleaseMutex(&unp->mx);
174
175         uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
176         lock_ObtainMutex(&uidp->mx);
177         uidp->unp = unp;
178                 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",(int)vcp,vcp->lana,vcp->lsn,newUid,usern);
179                 osi_Log4(afsd_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
180         lock_ReleaseMutex(&uidp->mx);
181         smb_ReleaseUID(uidp);
182     }
183
184     /* Return UID to the client */
185     ((smb_t *)outp)->uid = newUid;
186     /* Also to the next chained message */
187     ((smb_t *)inp)->uid = newUid;
188
189     osi_Log3(afsd_logp, "SMB3 session setup name %s creating ID %d%s",
190              osi_LogSaveString(afsd_logp, usern), newUid, osi_LogSaveString(afsd_logp, s1));
191     smb_SetSMBParm(outp, 2, 0);
192     smb_SetSMBDataLength(outp, 0);
193     return 0;
194 }
195
196 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
197 {
198         smb_user_t *uidp;
199
200         /* don't get tokens from this VC */
201         vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
202
203         inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
204
205         /* find the tree and free it */
206     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
207     /* TODO: smb_ReleaseUID() ? */
208     if (uidp) {
209                 char *s1 = NULL, *s2 = NULL;
210
211                 if (s2 == NULL) s2 = " ";
212                 if (s1 == NULL) {s1 = s2; s2 = " ";}
213
214                 osi_Log4(afsd_logp, "SMB3 user logoffX uid %d name %s%s%s",
215                          uidp->userID,
216                          osi_LogSaveString(afsd_logp,
217                  (uidp->unp) ? uidp->unp->name: " "), s1, s2);
218
219                 lock_ObtainMutex(&uidp->mx);
220                 uidp->flags |= SMB_USERFLAG_DELETE;
221                 /*
222                  * it doesn't get deleted right away
223                  * because the vcp points to it
224                  */
225                 lock_ReleaseMutex(&uidp->mx);
226         }
227         else
228                 osi_Log0(afsd_logp, "SMB3 user logoffX");
229
230         smb_SetSMBDataLength(outp, 0);
231         return 0;
232 }
233
234 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
235 {
236         smb_tid_t *tidp;
237         unsigned short newTid;
238         char shareName[256];
239         char *sharePath;
240         int shareFound;
241         char *tp;
242         char *pathp;
243         char *passwordp;
244         char *servicep;
245         cm_user_t *userp;
246         
247         osi_Log0(afsd_logp, "SMB3 receive tree connect");
248
249         /* parse input parameters */
250         tp = smb_GetSMBData(inp, NULL);
251         passwordp = smb_ParseString(tp, &tp);
252         pathp = smb_ParseString(tp, &tp);
253         servicep = smb_ParseString(tp, &tp);
254
255         tp = strrchr(pathp, '\\');
256         if (!tp) {
257                 return CM_ERROR_BADSMB;
258         }
259         strcpy(shareName, tp+1);
260
261         if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0)
262                 return CM_ERROR_NOIPC;
263
264         userp = smb_GetUser(vcp, inp);
265
266         lock_ObtainMutex(&vcp->mx);
267         newTid = vcp->tidCounter++;
268         lock_ReleaseMutex(&vcp->mx);
269         
270         tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
271         shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
272         if (!shareFound) {
273                 smb_ReleaseTID(tidp);
274                 return CM_ERROR_BADSHARENAME;
275         }
276         lock_ObtainMutex(&tidp->mx);
277         tidp->userp = userp;
278         tidp->pathname = sharePath;
279         lock_ReleaseMutex(&tidp->mx);
280         smb_ReleaseTID(tidp);
281
282         if (vcp->flags & SMB_VCFLAG_USENT)
283                 smb_SetSMBParm(outp, 2, 0);     /* OptionalSupport bits */
284
285         ((smb_t *)outp)->tid = newTid;
286         ((smb_t *)inp)->tid = newTid;
287         tp = smb_GetSMBData(outp, NULL);
288         *tp++ = 'A';
289         *tp++ = ':';
290         *tp++ = 0;
291         smb_SetSMBDataLength(outp, 3);
292         
293         osi_Log1(afsd_logp, "SMB3 tree connect created ID %d", newTid);
294         return 0;
295 }
296
297 /* must be called with global tran lock held */
298 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
299 {
300         smb_tran2Packet_t *tp;
301         smb_t *smbp;
302         
303         smbp = (smb_t *) inp->data;
304         for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
305                 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
306                         return tp;
307         }
308         return NULL;
309 }
310
311 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
312         int totalParms, int totalData)
313 {
314         smb_tran2Packet_t *tp;
315     smb_t *smbp;
316         
317     smbp = (smb_t *) inp->data;
318         tp = malloc(sizeof(*tp));
319     memset(tp, 0, sizeof(*tp));
320     tp->vcp = vcp;
321     smb_HoldVC(vcp);
322     tp->curData = tp->curParms = 0;
323     tp->totalData = totalData;
324     tp->totalParms = totalParms;
325     tp->tid = smbp->tid;
326     tp->mid = smbp->mid;
327     tp->uid = smbp->uid;
328     tp->pid = smbp->pid;
329         tp->res[0] = smbp->res[0];
330         osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
331     tp->opcode = smb_GetSMBParm(inp, 14);
332         if (totalParms != 0)
333         tp->parmsp = malloc(totalParms);
334         if (totalData != 0)
335         tp->datap = malloc(totalData);
336         tp->flags |= SMB_TRAN2PFLAG_ALLOC;
337     return tp;
338 }
339
340 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
341         smb_tran2Packet_t *inp, smb_packet_t *outp,
342         int totalParms, int totalData)
343 {
344         smb_tran2Packet_t *tp;
345         unsigned short parmOffset;
346         unsigned short dataOffset;
347         unsigned short dataAlign;
348         
349         tp = malloc(sizeof(*tp));
350         memset(tp, 0, sizeof(*tp));
351         tp->vcp = NULL;
352         tp->curData = tp->curParms = 0;
353         tp->totalData = totalData;
354         tp->totalParms = totalParms;
355         tp->oldTotalParms = totalParms;
356         tp->tid = inp->tid;
357         tp->mid = inp->mid;
358         tp->uid = inp->uid;
359         tp->pid = inp->pid;
360         tp->res[0] = inp->res[0];
361         tp->opcode = inp->opcode;
362
363         /*
364          * We calculate where the parameters and data will start.
365          * This calculation must parallel the calculation in
366          * smb_SendTran2Packet.
367          */
368
369         parmOffset = 10*2 + 35;
370         parmOffset++;                   /* round to even */
371         tp->parmsp = (unsigned short *) (outp->data + parmOffset);
372
373         dataOffset = parmOffset + totalParms;
374         dataAlign = dataOffset & 2;     /* quad-align */
375         dataOffset += dataAlign;
376         tp->datap = outp->data + dataOffset;
377
378         return tp;
379 }
380
381 /* free a tran2 packet; must be called with smb_globalLock held */
382 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
383 {
384     if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
385         if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
386                 if (t2p->parmsp)
387                         free(t2p->parmsp);
388                 if (t2p->datap)
389                         free(t2p->datap);
390         }
391     free(t2p);
392 }
393
394 /* called with a VC, an input packet to respond to, and an error code.
395  * sends an error response.
396  */
397 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
398         smb_packet_t *tp, long code)
399 {
400         smb_t *smbp;
401         unsigned short errCode;
402         unsigned char errClass;
403         unsigned long NTStatus;
404
405         if (vcp->flags & SMB_VCFLAG_STATUS32)
406                 smb_MapNTError(code, &NTStatus);
407         else
408                 smb_MapCoreError(code, vcp, &errCode, &errClass);
409
410         smb_FormatResponsePacket(vcp, NULL, tp);
411         smbp = (smb_t *) tp;
412         
413         /* We can handle long names */
414         if (vcp->flags & SMB_VCFLAG_USENT)
415                 smbp->flg2 |= 0x40;     /* IS_LONG_NAME */
416         
417         /* now copy important fields from the tran 2 packet */
418         smbp->com = 0x32;               /* tran 2 response */
419         smbp->tid = t2p->tid;
420         smbp->mid = t2p->mid;
421         smbp->pid = t2p->pid;
422         smbp->uid = t2p->uid;
423         smbp->res[0] = t2p->res[0];
424         if (vcp->flags & SMB_VCFLAG_STATUS32) {
425                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
426                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
427                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
428                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
429                 smbp->flg2 |= 0x4000;
430         }
431         else {
432                 smbp->rcls = errClass;
433                 smbp->errLow = (unsigned char) (errCode & 0xff);
434                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
435         }
436         
437         /* send packet */
438         smb_SendPacket(vcp, tp);
439 }        
440
441 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
442 {
443         smb_t *smbp;
444         unsigned short parmOffset;
445         unsigned short dataOffset;
446         unsigned short totalLength;
447         unsigned short dataAlign;
448         char *datap;
449         
450         smb_FormatResponsePacket(vcp, NULL, tp);
451         smbp = (smb_t *) tp;
452
453         /* We can handle long names */
454         if (vcp->flags & SMB_VCFLAG_USENT)
455                 smbp->flg2 |= 0x40;     /* IS_LONG_NAME */
456         
457         /* now copy important fields from the tran 2 packet */
458         smbp->com = 0x32;               /* tran 2 response */
459         smbp->tid = t2p->tid;
460         smbp->mid = t2p->mid;
461         smbp->pid = t2p->pid;
462         smbp->uid = t2p->uid;
463         smbp->res[0] = t2p->res[0];
464
465         totalLength = 1 + t2p->totalData + t2p->totalParms;
466
467         /* now add the core parameters (tran2 info) to the packet */
468         smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
469         smb_SetSMBParm(tp, 1, t2p->totalData);  /* data bytes */
470         smb_SetSMBParm(tp, 2, 0);               /* reserved */
471         smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
472         parmOffset = 10*2 + 35;                 /* parm offset in packet */
473         parmOffset++;                           /* round to even */
474         smb_SetSMBParm(tp, 4, parmOffset);      /* 11 parm words plus *
475                                                  * hdr, bcc and wct */
476         smb_SetSMBParm(tp, 5, 0);               /* parm displacement */
477         smb_SetSMBParm(tp, 6, t2p->totalData);  /* data in this packet */
478         dataOffset = parmOffset + t2p->oldTotalParms;
479         dataAlign = dataOffset & 2;             /* quad-align */
480         dataOffset += dataAlign;
481         smb_SetSMBParm(tp, 7, dataOffset);      /* offset of data */
482         smb_SetSMBParm(tp, 8, 0);               /* data displacement */
483         smb_SetSMBParm(tp, 9, 0);               /* low: setup word count *
484                                                  * high: resvd */
485         
486         datap = smb_GetSMBData(tp, NULL);
487         *datap++ = 0;                           /* we rounded to even */
488
489         totalLength += dataAlign;
490         smb_SetSMBDataLength(tp, totalLength);
491         
492         /* next, send the datagram */
493         smb_SendPacket(vcp, tp);
494 }
495
496 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
497 {
498         smb_tran2Packet_t *asp;
499         int totalParms;
500         int totalData;
501         int parmDisp;
502         int dataDisp;
503         int parmOffset;
504         int dataOffset;
505         int parmCount;
506         int dataCount;
507         int firstPacket;
508         long code;
509
510         /* We sometimes see 0 word count.  What to do? */
511         if (*inp->wctp == 0) {
512 #ifndef DJGPP
513                 HANDLE h;
514                 char *ptbuf[1];
515
516                 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0"); 
517
518                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
519                 ptbuf[0] = "Transaction2 word count = 0";
520                 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
521                             1, inp->ncb_length, ptbuf, inp);
522                 DeregisterEventSource(h);
523 #else /* DJGPP */
524                 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0"); 
525 #endif /* !DJGPP */
526
527                 smb_SetSMBDataLength(outp, 0);
528                 smb_SendPacket(vcp, outp);
529                 return 0;
530         }
531
532         totalParms = smb_GetSMBParm(inp, 0);
533         totalData = smb_GetSMBParm(inp, 1);
534         
535         firstPacket = (inp->inCom == 0x32);
536         
537         /* find the packet we're reassembling */
538         lock_ObtainWrite(&smb_globalLock);
539         asp = smb_FindTran2Packet(vcp, inp);
540         if (!asp) {
541                 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
542         }
543         lock_ReleaseWrite(&smb_globalLock);
544         
545         /* now merge in this latest packet; start by looking up offsets */
546         if (firstPacket) {
547                 parmDisp = dataDisp = 0;
548                 parmOffset = smb_GetSMBParm(inp, 10);
549                 dataOffset = smb_GetSMBParm(inp, 12);
550                 parmCount = smb_GetSMBParm(inp, 9);
551                 dataCount = smb_GetSMBParm(inp, 11);
552                 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
553                 asp->maxReturnData = smb_GetSMBParm(inp, 3);
554
555                 osi_Log3(afsd_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
556                         totalData, dataCount, asp->maxReturnData);
557         }
558         else {
559                 parmDisp = smb_GetSMBParm(inp, 4);
560                 parmOffset = smb_GetSMBParm(inp, 3);
561                 dataDisp = smb_GetSMBParm(inp, 7);
562                 dataOffset = smb_GetSMBParm(inp, 6);
563                 parmCount = smb_GetSMBParm(inp, 2);
564                 dataCount = smb_GetSMBParm(inp, 5);
565                 
566                 osi_Log2(afsd_logp, "SMB3 received T2 aux packet parms %d, data %d",
567                         parmCount, dataCount);
568         }
569
570     /* now copy the parms and data */
571     if ( parmCount != 0 )
572     {
573         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
574     }
575     if ( dataCount != 0 ) {
576         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
577     }
578
579         /* account for new bytes */
580         asp->curData += dataCount;
581         asp->curParms += parmCount;
582         
583         /* finally, if we're done, remove the packet from the queue and dispatch it */
584         if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
585                 /* we've received it all */
586                 lock_ObtainWrite(&smb_globalLock);
587                 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
588                 lock_ReleaseWrite(&smb_globalLock);
589                 
590             /* now dispatch it */
591             if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
592                 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
593                 osi_Log4(afsd_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
594                 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
595             }
596             else {
597                 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
598                 osi_Log4(afsd_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
599                 code = CM_ERROR_BADOP;
600             }
601
602                 /* if an error is returned, we're supposed to send an error packet,
603                  * otherwise the dispatched function already did the data sending.
604                  * We give dispatched proc the responsibility since it knows how much
605                  * space to allocate.
606                  */
607                 if (code != 0) {
608                         smb_SendTran2Error(vcp, asp, outp, code);
609                 }
610
611                 /* free the input tran 2 packet */
612                 lock_ObtainWrite(&smb_globalLock);
613                 smb_FreeTran2Packet(asp);
614                 lock_ReleaseWrite(&smb_globalLock);
615         }
616         else if (firstPacket) {
617                 /* the first packet in a multi-packet request, we need to send an
618                  * ack to get more data.
619                  */
620                 smb_SetSMBDataLength(outp, 0);
621                 smb_SendPacket(vcp, outp);
622         }
623
624         return 0;
625 }
626
627 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
628 {
629         char *pathp;
630     smb_tran2Packet_t *outp;
631     long code;
632         cm_space_t *spacep;
633     int excl;
634     cm_user_t *userp;
635     cm_scache_t *dscp;          /* dir we're dealing with */
636     cm_scache_t *scp;           /* file we're creating */
637     cm_attr_t setAttr;
638     int initialModeBits;
639     smb_fid_t *fidp;
640     int attributes;
641     char *lastNamep;
642     long dosTime;
643     int openFun;
644     int trunc;
645     int openMode;
646     int extraInfo;
647     int openAction;
648     int parmSlot;                       /* which parm we're dealing with */
649     long returnEALength;
650         char *tidPathp;
651         cm_req_t req;
652
653         cm_InitReq(&req);
654
655     scp = NULL;
656         
657         extraInfo = (p->parmsp[0] & 1); /* return extra info */
658     returnEALength = (p->parmsp[0] & 8);        /* return extended attr length */
659
660         openFun = p->parmsp[6];         /* open function */
661     excl = ((openFun & 3) == 0);
662     trunc = ((openFun & 3) == 2);       /* truncate it */
663         openMode = (p->parmsp[1] & 0x7);
664     openAction = 0;                     /* tracks what we did */
665
666     attributes = p->parmsp[3];
667     dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
668         
669         /* compute initial mode bits based on read-only flag in attributes */
670     initialModeBits = 0666;
671     if (attributes & 1) initialModeBits &= ~0222;
672         
673     pathp = (char *) (&p->parmsp[14]);
674         
675     outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
676
677         spacep = cm_GetSpace();
678     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
679
680         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
681                 /* special case magic file name for receiving IOCTL requests
682          * (since IOCTL calls themselves aren't getting through).
683          */
684         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
685         smb_SetupIoctlFid(fidp, spacep);
686
687         /* copy out remainder of the parms */
688                 parmSlot = 0;
689                 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
690                 if (extraInfo) {
691             outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
692             outp->parmsp[parmSlot] = 0; parmSlot++;     /* mod time */
693             outp->parmsp[parmSlot] = 0; parmSlot++;
694             outp->parmsp[parmSlot] = 0; parmSlot++;     /* len */
695             outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
696             outp->parmsp[parmSlot] = openMode; parmSlot++;
697             outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
698             outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
699                 }   
700                 /* and the final "always present" stuff */
701         outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
702                 /* next write out the "unique" ID */
703                 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
704                 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
705         outp->parmsp[parmSlot] = 0; parmSlot++;
706                 if (returnEALength) {
707                         outp->parmsp[parmSlot] = 0; parmSlot++;
708                         outp->parmsp[parmSlot] = 0; parmSlot++;
709         }
710                 
711         outp->totalData = 0;
712         outp->totalParms = parmSlot * 2;
713                 
714         smb_SendTran2Packet(vcp, outp, op);
715                 
716         smb_FreeTran2Packet(outp);
717
718                 /* and clean up fid reference */
719         smb_ReleaseFID(fidp);
720         return 0;
721     }
722
723 #ifdef DEBUG_VERBOSE
724         {
725                 char *hexp, *asciip;
726                 asciip = (lastNamep ? lastNamep : pathp);
727                 hexp = osi_HexifyString( asciip );
728                 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
729                 free(hexp);
730         }
731 #endif
732
733         userp = smb_GetTran2User(vcp, p);
734     /* In the off chance that userp is NULL, we log and abandon */
735     if(!userp) {
736         osi_Log1(afsd_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
737         smb_FreeTran2Packet(outp);
738         return CM_ERROR_BADSMB;
739     }
740
741         tidPathp = smb_GetTIDPath(vcp, p->tid);
742
743         dscp = NULL;
744         code = cm_NameI(cm_rootSCachep, pathp,
745                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
746                     userp, tidPathp, &req, &scp);
747         if (code != 0) {
748                 code = cm_NameI(cm_rootSCachep, spacep->data,
749                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
750                         userp, tidPathp, &req, &dscp);
751                 cm_FreeSpace(spacep);
752
753         if (code) {
754             cm_ReleaseUser(userp);
755                         smb_FreeTran2Packet(outp);
756             return code;
757         }
758         
759         /* otherwise, scp points to the parent directory.  Do a lookup,
760                  * and truncate the file if we find it, otherwise we create the
761                  * file.
762          */
763         if (!lastNamep) lastNamep = pathp;
764         else lastNamep++;
765         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
766                          &req, &scp);
767         if (code && code != CM_ERROR_NOSUCHFILE) {
768                         cm_ReleaseSCache(dscp);
769             cm_ReleaseUser(userp);
770                         smb_FreeTran2Packet(outp);
771             return code;
772         }
773         }
774     else {
775         cm_FreeSpace(spacep);
776         }
777         
778     /* if we get here, if code is 0, the file exists and is represented by
779      * scp.  Otherwise, we have to create it.
780      */
781         if (code == 0) {
782         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
783         if (code) {
784             if (dscp) cm_ReleaseSCache(dscp);
785             cm_ReleaseSCache(scp);
786             cm_ReleaseUser(userp);
787                         smb_FreeTran2Packet(outp);
788             return code;
789         }
790
791                 if (excl) {
792                         /* oops, file shouldn't be there */
793             if (dscp) cm_ReleaseSCache(dscp);
794             cm_ReleaseSCache(scp);
795             cm_ReleaseUser(userp);
796                         smb_FreeTran2Packet(outp);
797             return CM_ERROR_EXISTS;
798         }
799
800                 if (trunc) {
801                         setAttr.mask = CM_ATTRMASK_LENGTH;
802             setAttr.length.LowPart = 0;
803             setAttr.length.HighPart = 0;
804                         code = cm_SetAttr(scp, &setAttr, userp, &req);
805             openAction = 3;     /* truncated existing file */
806                 }   
807         else openAction = 1;    /* found existing file */
808     }
809         else if (!(openFun & SMB_ATTR_DIRECTORY)) {
810                 /* don't create if not found */
811         if (dscp) cm_ReleaseSCache(dscp);
812         osi_assert(scp == NULL);
813         cm_ReleaseUser(userp);
814                 smb_FreeTran2Packet(outp);
815         return CM_ERROR_NOSUCHFILE;
816     }
817     else {
818                 osi_assert(dscp != NULL && scp == NULL);
819                 openAction = 2; /* created file */
820                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
821                 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
822         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
823                          &req);
824                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
825                         smb_NotifyChange(FILE_ACTION_ADDED,
826                              FILE_NOTIFY_CHANGE_FILE_NAME,  
827                              dscp, lastNamep, NULL, TRUE);
828         if (!excl && code == CM_ERROR_EXISTS) {
829                         /* not an exclusive create, and someone else tried
830                          * creating it already, then we open it anyway.  We
831                          * don't bother retrying after this, since if this next
832                          * fails, that means that the file was deleted after we
833                          * started this call.
834              */
835             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
836                              userp, &req, &scp);
837             if (code == 0) {
838                 if (trunc) {
839                                         setAttr.mask = CM_ATTRMASK_LENGTH;
840                     setAttr.length.LowPart = 0;
841                     setAttr.length.HighPart = 0;
842                     code = cm_SetAttr(scp, &setAttr, userp,
843                                       &req);
844                 }   
845                         }       /* lookup succeeded */
846         }
847     }
848         
849         /* we don't need this any longer */
850         if (dscp) cm_ReleaseSCache(dscp);
851
852     if (code) {
853                 /* something went wrong creating or truncating the file */
854         if (scp) cm_ReleaseSCache(scp);
855         cm_ReleaseUser(userp);
856                 smb_FreeTran2Packet(outp);
857         return code;
858     }
859         
860         /* make sure we're about to open a file */
861         if (scp->fileType != CM_SCACHETYPE_FILE) {
862                 cm_ReleaseSCache(scp);
863                 cm_ReleaseUser(userp);
864                 smb_FreeTran2Packet(outp);
865                 return CM_ERROR_ISDIR;
866         }
867
868     /* now all we have to do is open the file itself */
869     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
870     osi_assert(fidp);
871         
872         /* save a pointer to the vnode */
873     fidp->scp = scp;
874         
875         /* compute open mode */
876     if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
877     if (openMode == 1 || openMode == 2)
878         fidp->flags |= SMB_FID_OPENWRITE;
879
880         smb_ReleaseFID(fidp);
881         
882         cm_Open(scp, 0, userp);
883
884     /* copy out remainder of the parms */
885         parmSlot = 0;
886         outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
887         lock_ObtainMutex(&scp->mx);
888         if (extraInfo) {
889         outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
890                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
891         outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
892         outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
893         outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
894         parmSlot++;
895         outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
896         parmSlot++;
897         outp->parmsp[parmSlot] = openMode; parmSlot++;
898         outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
899         outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
900         }   
901         /* and the final "always present" stuff */
902     outp->parmsp[parmSlot] = openAction; parmSlot++;
903         /* next write out the "unique" ID */
904         outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
905         outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
906     outp->parmsp[parmSlot] = 0; parmSlot++;
907     if (returnEALength) {
908                 outp->parmsp[parmSlot] = 0; parmSlot++;
909                 outp->parmsp[parmSlot] = 0; parmSlot++;
910     }
911         lock_ReleaseMutex(&scp->mx);
912         outp->totalData = 0;            /* total # of data bytes */
913     outp->totalParms = parmSlot * 2;    /* shorts are two bytes */
914
915         smb_SendTran2Packet(vcp, outp, op);
916         
917     smb_FreeTran2Packet(outp);
918
919     cm_ReleaseUser(userp);
920     /* leave scp held since we put it in fidp->scp */
921     return 0;
922 }   
923
924 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
925 {
926         return CM_ERROR_BADOP;
927 }
928
929 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
930 {
931         return CM_ERROR_BADOP;
932 }
933
934 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
935 {
936         smb_tran2Packet_t *outp;
937         smb_tran2QFSInfo_t qi;
938         int responseSize;
939         osi_hyper_t temp;
940         static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
941         
942         osi_Log1(afsd_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
943
944         switch (p->parmsp[0]) {
945         case 1: responseSize = sizeof(qi.u.allocInfo); break;
946         case 2: responseSize = sizeof(qi.u.volumeInfo); break;
947         case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
948         case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
949         case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
950         case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
951         default: return CM_ERROR_INVAL;
952         }
953
954         outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
955         switch (p->parmsp[0]) {
956         case 1:
957                 /* alloc info */
958                 qi.u.allocInfo.FSID = 0;
959                 qi.u.allocInfo.sectorsPerAllocUnit = 1;
960                 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
961                 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
962                 qi.u.allocInfo.bytesPerSector = 1024;
963                 break;
964
965         case 2:
966                 /* volume info */
967         qi.u.volumeInfo.vsn = 1234;
968         qi.u.volumeInfo.vnCount = 4;
969                 /* we're supposed to pad it out with zeroes to the end */
970                 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
971         memcpy(qi.u.volumeInfo.label, "AFS", 4);
972                 break;
973
974         case 0x102:
975                 /* FS volume info */
976                 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
977                 qi.u.FSvolumeInfo.vsn = 1234;
978                 qi.u.FSvolumeInfo.vnCount = 8;
979                 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
980                 break;
981
982         case 0x103:
983                 /* FS size info */
984                 temp.HighPart = 0;
985                 temp.LowPart = 0x7fffffff;
986                 qi.u.FSsizeInfo.totalAllocUnits = temp;
987                 temp.LowPart = 0x3fffffff;
988                 qi.u.FSsizeInfo.availAllocUnits = temp;
989                 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
990                 qi.u.FSsizeInfo.bytesPerSector = 1024;
991                 break;
992
993         case 0x104:
994                 /* FS device info */
995                 qi.u.FSdeviceInfo.devType = 0;  /* don't have a number */
996                 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
997                 break;
998
999         case 0x105:
1000                 /* FS attribute info */
1001                 /* attributes, defined in WINNT.H:
1002                  *      FILE_CASE_SENSITIVE_SEARCH      0x1
1003                  *      FILE_CASE_PRESERVED_NAMES       0x2
1004                  *      <no name defined>               0x4000
1005                  *         If bit 0x4000 is not set, Windows 95 thinks
1006                  *         we can't handle long (non-8.3) names,
1007                  *         despite our protestations to the contrary.
1008                  */
1009                 qi.u.FSattributeInfo.attributes = 0x4003;
1010                 qi.u.FSattributeInfo.maxCompLength = 255;
1011                 qi.u.FSattributeInfo.FSnameLength = 6;
1012                 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
1013                 break;
1014         }
1015         
1016         /* copy out return data, and set corresponding sizes */
1017         outp->totalParms = 0;
1018         outp->totalData = responseSize;
1019         memcpy(outp->datap, &qi, responseSize);
1020
1021         /* send and free the packets */
1022         smb_SendTran2Packet(vcp, outp, op);
1023         smb_FreeTran2Packet(outp);
1024
1025         return 0;
1026 }
1027
1028 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1029 {
1030         return CM_ERROR_BADOP;
1031 }
1032
1033 struct smb_ShortNameRock {
1034         char *maskp;
1035         unsigned int vnode;
1036         char *shortName;
1037         size_t shortNameLen;
1038 };
1039
1040 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
1041         osi_hyper_t *offp)
1042 {
1043         struct smb_ShortNameRock *rockp;
1044         char *shortNameEnd;
1045
1046         rockp = vrockp;
1047         /* compare both names and vnodes, though probably just comparing vnodes
1048          * would be safe enough.
1049          */
1050         if (stricmp(dep->name, rockp->maskp) != 0)
1051                 return 0;
1052         if (ntohl(dep->fid.vnode) != rockp->vnode)
1053                 return 0;
1054         /* This is the entry */
1055         cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1056         rockp->shortNameLen = shortNameEnd - rockp->shortName;
1057         return CM_ERROR_STOPNOW;
1058 }
1059
1060 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1061         char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1062 {
1063         struct smb_ShortNameRock rock;
1064         char *lastNamep;
1065         cm_space_t *spacep;
1066         cm_scache_t *dscp;
1067         int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1068         long code;
1069         osi_hyper_t thyper;
1070
1071         spacep = cm_GetSpace();
1072         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1073
1074         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1075                         reqp, &dscp);
1076         cm_FreeSpace(spacep);
1077         if (code) return code;
1078
1079         if (!lastNamep) lastNamep = pathp;
1080         else lastNamep++;
1081         thyper.LowPart = 0;
1082         thyper.HighPart = 0;
1083         rock.shortName = shortName;
1084         rock.vnode = vnode;
1085         rock.maskp = lastNamep;
1086         code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1087                            reqp, NULL);
1088
1089         cm_ReleaseSCache(dscp);
1090
1091         if (code == 0)
1092                 return CM_ERROR_NOSUCHFILE;
1093         if (code == CM_ERROR_STOPNOW) {
1094                 *shortNameLenp = rock.shortNameLen;
1095                 return 0;
1096         }
1097         return code;
1098 }
1099
1100 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1101 {
1102         smb_tran2Packet_t *outp;
1103         unsigned long dosTime;
1104         FILETIME ft;
1105         unsigned short infoLevel;
1106         int nbytesRequired;
1107         unsigned short attributes;
1108         unsigned long extAttributes;
1109         char shortName[13];
1110         unsigned int len;
1111         cm_user_t *userp;
1112         cm_space_t *spacep;
1113         cm_scache_t *scp, *dscp;
1114         long code;
1115         char *op;
1116         char *tidPathp;
1117         char *lastComp;
1118         cm_req_t req;
1119
1120         cm_InitReq(&req);
1121
1122         infoLevel = p->parmsp[0];
1123         if (infoLevel == 6) nbytesRequired = 0;
1124         else if (infoLevel == 1) nbytesRequired = 22;
1125         else if (infoLevel == 2) nbytesRequired = 26;
1126         else if (infoLevel == 0x101) nbytesRequired = 40;
1127         else if (infoLevel == 0x102) nbytesRequired = 24;
1128         else if (infoLevel == 0x103) nbytesRequired = 4;
1129         else if (infoLevel == 0x108) nbytesRequired = 30;
1130         else {
1131                 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1132                          p->opcode, infoLevel);
1133                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1134                 return 0;
1135         }
1136         osi_Log2(afsd_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1137                  osi_LogSaveString(afsd_logp, (char *)(&p->parmsp[3])));
1138
1139         outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1140
1141         if (infoLevel > 0x100)
1142                 outp->totalParms = 2;
1143         else
1144                 outp->totalParms = 0;
1145         outp->totalData = nbytesRequired;
1146         
1147         /* now, if we're at infoLevel 6, we're only being asked to check
1148          * the syntax, so we just OK things now.  In particular, we're *not*
1149          * being asked to verify anything about the state of any parent dirs.
1150          */
1151         if (infoLevel == 6) {
1152                 smb_SendTran2Packet(vcp, outp, opx);
1153                 smb_FreeTran2Packet(outp);
1154                 return 0;
1155         }
1156         
1157         userp = smb_GetTran2User(vcp, p);
1158         if(!userp) {
1159                 osi_Log1(afsd_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
1160                 smb_FreeTran2Packet(outp);
1161                 return CM_ERROR_BADSMB;
1162         }
1163
1164         tidPathp = smb_GetTIDPath(vcp, p->tid);
1165
1166         /*
1167          * XXX Strange hack XXX
1168          *
1169          * As of Patch 7 (13 January 98), we are having the following problem:
1170          * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1171          * requests to look up "desktop.ini" in all the subdirectories.
1172          * This can cause zillions of timeouts looking up non-existent cells
1173          * and volumes, especially in the top-level directory.
1174          *
1175          * We have not found any way to avoid this or work around it except
1176          * to explicitly ignore the requests for mount points that haven't
1177          * yet been evaluated and for directories that haven't yet been
1178          * fetched.
1179          */
1180         if (infoLevel == 0x101) {
1181                 spacep = cm_GetSpace();
1182                 smb_StripLastComponent(spacep->data, &lastComp,
1183                                         (char *)(&p->parmsp[3]));
1184                 /* Make sure that lastComp is not NULL */
1185                 if (lastComp) {
1186                     if (strcmp(lastComp, "\\desktop.ini") == 0) {
1187                 code = cm_NameI(cm_rootSCachep, spacep->data,
1188                                 CM_FLAG_CASEFOLD
1189                                 | CM_FLAG_DIRSEARCH
1190                                 | CM_FLAG_FOLLOW,
1191                                 userp, tidPathp, &req, &dscp);
1192                 if (code == 0) {
1193                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1194                          && !dscp->mountRootFidp)
1195                         code = CM_ERROR_NOSUCHFILE;
1196                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1197                         cm_buf_t *bp = buf_Find(dscp, &hzero);
1198                         if (bp)
1199                             buf_Release(bp);
1200                         else
1201                             code = CM_ERROR_NOSUCHFILE;
1202                     }
1203                     cm_ReleaseSCache(dscp);
1204                     if (code) {
1205                         cm_FreeSpace(spacep);
1206                         cm_ReleaseUser(userp);
1207                         smb_SendTran2Error(vcp, p, opx, code);
1208                         smb_FreeTran2Packet(outp);
1209                         return 0;
1210                     }
1211                 }
1212             }
1213         }
1214                 cm_FreeSpace(spacep);
1215         }
1216
1217         /* now do namei and stat, and copy out the info */
1218         code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1219                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1220
1221         if (code) {
1222                 cm_ReleaseUser(userp);
1223                 smb_SendTran2Error(vcp, p, opx, code);
1224                 smb_FreeTran2Packet(outp);
1225                 return 0;
1226         }
1227
1228         lock_ObtainMutex(&scp->mx);
1229         code = cm_SyncOp(scp, NULL, userp, &req, 0,
1230                 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1231         if (code) goto done;
1232         
1233         /* now we have the status in the cache entry, and everything is locked.
1234          * Marshall the output data.
1235          */
1236         op = outp->datap;
1237         /* for info level 108, figure out short name */
1238         if (infoLevel == 0x108) {
1239                 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1240                                         tidPathp, scp->fid.vnode, shortName,
1241                                         (size_t *) &len);
1242                 if (code) {
1243                         goto done;
1244                 }
1245
1246                 op = outp->datap;
1247                 *((u_long *)op) = len * 2; op += 4;
1248                 mbstowcs((unsigned short *)op, shortName, len);
1249                 op += (len * 2);
1250
1251                 goto done;
1252         }
1253         if (infoLevel == 1 || infoLevel == 2) {
1254                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1255                 *((u_long *)op) = dosTime; op += 4;     /* creation time */
1256                 *((u_long *)op) = dosTime; op += 4;     /* access time */
1257                 *((u_long *)op) = dosTime; op += 4;     /* write time */
1258                 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1259                 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1260                 attributes = smb_Attributes(scp);
1261                 *((u_short *)op) = attributes; op += 2; /* attributes */
1262         }
1263         else if (infoLevel == 0x101) {
1264                 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1265                 *((FILETIME *)op) = ft; op += 8;        /* creation time */
1266                 *((FILETIME *)op) = ft; op += 8;        /* last access time */
1267                 *((FILETIME *)op) = ft; op += 8;        /* last write time */
1268                 *((FILETIME *)op) = ft; op += 8;        /* last change time */
1269                 extAttributes = smb_ExtAttributes(scp);
1270                 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1271                 *((u_long *)op) = 0; op += 4;   /* don't know what this is */
1272         }
1273         else if (infoLevel == 0x102) {
1274                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
1275                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
1276                 *((u_long *)op) = scp->linkCount; op += 4;
1277                 *op++ = 0;
1278                 *op++ = 0;
1279                 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1280                 *op++ = 0;
1281         }
1282         else if (infoLevel == 0x103) {
1283                 memset(op, 0, 4); op += 4;      /* EA size */
1284         }
1285
1286         /* now, if we are being asked about extended attrs, return a 0 size */
1287         if (infoLevel == 2) {
1288                 *((u_long *)op) = 0; op += 4;
1289         }
1290         
1291
1292         /* send and free the packets */
1293 done:
1294         lock_ReleaseMutex(&scp->mx);
1295         cm_ReleaseSCache(scp);
1296         cm_ReleaseUser(userp);
1297         if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1298         else smb_SendTran2Error(vcp, p, opx, code);
1299         smb_FreeTran2Packet(outp);
1300
1301         return 0;
1302 }
1303
1304 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1305 {
1306         return CM_ERROR_BADOP;
1307 }
1308
1309 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1310 {
1311         smb_tran2Packet_t *outp;
1312         FILETIME ft;
1313         unsigned long attributes;
1314         unsigned short infoLevel;
1315         int nbytesRequired;
1316         unsigned short fid;
1317         cm_user_t *userp;
1318     smb_fid_t *fidp;
1319         cm_scache_t *scp;
1320         char *op;
1321         long code;
1322         cm_req_t req;
1323
1324         cm_InitReq(&req);
1325
1326     fid = p->parmsp[0];
1327     fidp = smb_FindFID(vcp, fid, 0);
1328
1329         if (fidp == NULL) {
1330                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
1331                 return 0;
1332         }
1333
1334         infoLevel = p->parmsp[1];
1335         if (infoLevel == 0x101) nbytesRequired = 40;
1336         else if (infoLevel == 0x102) nbytesRequired = 24;
1337         else if (infoLevel == 0x103) nbytesRequired = 4;
1338         else if (infoLevel == 0x104) nbytesRequired = 6;
1339         else {
1340                 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1341                  p->opcode, infoLevel);
1342                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1343         smb_ReleaseFID(fidp);
1344                 return 0;
1345         }
1346         osi_Log2(afsd_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1347
1348         outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1349
1350         if (infoLevel > 0x100)
1351                 outp->totalParms = 2;
1352         else
1353                 outp->totalParms = 0;
1354         outp->totalData = nbytesRequired;
1355
1356         userp = smb_GetTran2User(vcp, p);
1357     if(!userp) {
1358         osi_Log1(afsd_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
1359         code = CM_ERROR_BADSMB;
1360         goto done;
1361     }
1362
1363         scp = fidp->scp;
1364         lock_ObtainMutex(&scp->mx);
1365         code = cm_SyncOp(scp, NULL, userp, &req, 0,
1366                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1367         if (code) goto done;
1368
1369         /* now we have the status in the cache entry, and everything is locked.
1370          * Marshall the output data.
1371          */
1372         op = outp->datap;
1373         if (infoLevel == 0x101) {
1374                 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1375                 *((FILETIME *)op) = ft; op += 8;        /* creation time */
1376                 *((FILETIME *)op) = ft; op += 8;        /* last access time */
1377                 *((FILETIME *)op) = ft; op += 8;        /* last write time */
1378                 *((FILETIME *)op) = ft; op += 8;        /* last change time */
1379                 attributes = smb_ExtAttributes(scp);
1380                 *((u_long *)op) = attributes; op += 4;
1381                 *((u_long *)op) = 0; op += 4;
1382         }
1383         else if (infoLevel == 0x102) {
1384                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
1385                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
1386                 *((u_long *)op) = scp->linkCount; op += 4;
1387                 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1388                 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1389                 *op++ = 0;
1390                 *op++ = 0;
1391         }
1392         else if (infoLevel == 0x103) {
1393                 *((u_long *)op) = 0; op += 4;
1394         }
1395         else if (infoLevel == 0x104) {
1396                 unsigned long len;
1397                 char *name;
1398
1399                 if (fidp->NTopen_wholepathp)
1400                         name = fidp->NTopen_wholepathp;
1401                 else
1402                         name = "\\";    /* probably can't happen */
1403                 len = strlen(name);
1404                 outp->totalData = (len*2) + 4;  /* this is actually what we want to return */
1405                 *((u_long *)op) = len * 2; op += 4;
1406                 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1407         }
1408
1409         /* send and free the packets */
1410 done:
1411         lock_ReleaseMutex(&scp->mx);
1412         cm_ReleaseUser(userp);
1413         smb_ReleaseFID(fidp);
1414         if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1415         else smb_SendTran2Error(vcp, p, opx, code);
1416         smb_FreeTran2Packet(outp);
1417
1418         return 0;
1419 }
1420
1421 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1422 {
1423         long code;
1424         unsigned short fid;
1425         smb_fid_t *fidp;
1426         unsigned short infoLevel;
1427         smb_tran2Packet_t *outp;
1428         cm_user_t *userp;
1429         cm_scache_t *scp;
1430         cm_req_t req;
1431
1432         cm_InitReq(&req);
1433
1434     fid = p->parmsp[0];
1435         fidp = smb_FindFID(vcp, fid, 0);
1436
1437         if (fidp == NULL) {
1438                 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1439                 return 0;
1440         }
1441
1442         infoLevel = p->parmsp[1];
1443         if (infoLevel > 0x104 || infoLevel < 0x101) {
1444                 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1445                          p->opcode, infoLevel);
1446                 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1447         smb_ReleaseFID(fidp);
1448                 return 0;
1449         }
1450
1451         if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1452                 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1453         smb_ReleaseFID(fidp);
1454                 return 0;
1455         }
1456         if ((infoLevel == 0x103 || infoLevel == 0x104)
1457             && !(fidp->flags & SMB_FID_OPENWRITE)) {
1458                 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1459         smb_ReleaseFID(fidp);
1460                 return 0;
1461         }
1462
1463         osi_Log1(afsd_logp, "T2 SFileInfo type 0x%x", infoLevel);
1464
1465         outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1466
1467         outp->totalParms = 2;
1468         outp->totalData = 0;
1469
1470         userp = smb_GetTran2User(vcp, p);
1471     if(!userp) {
1472         osi_Log1(afsd_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
1473         code = CM_ERROR_BADSMB;
1474         goto done;
1475     }
1476
1477         scp = fidp->scp;
1478
1479         if (infoLevel == 0x101) {
1480                 FILETIME lastMod;
1481                 unsigned int attribute;
1482                 cm_attr_t attr;
1483
1484                 /* lock the vnode with a callback; we need the current status
1485                  * to determine what the new status is, in some cases.
1486                  */
1487                 lock_ObtainMutex(&scp->mx);
1488                 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1489                          CM_SCACHESYNC_GETSTATUS
1490                          | CM_SCACHESYNC_NEEDCALLBACK);
1491                 if (code) {
1492                         lock_ReleaseMutex(&scp->mx);
1493                         goto done;
1494                 }
1495
1496                 /* prepare for setattr call */
1497                 attr.mask = 0;
1498                 
1499                 lastMod = *((FILETIME *)(p->datap + 16));
1500                 /* when called as result of move a b, lastMod is (-1, -1). 
1501          * If the check for -1 is not present, timestamp
1502                  * of the resulting file will be 1969 (-1)
1503                  */
1504                 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && 
1505             lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
1506                         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1507                         smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1508                                                         &lastMod);
1509                         fidp->flags |= SMB_FID_MTIMESETDONE;
1510                 }
1511                 
1512                 attribute = *((u_long *)(p->datap + 32));
1513                 if (attribute != 0) {
1514                         if ((scp->unixModeBits & 0222)
1515                             && (attribute & 1) != 0) {
1516                                 /* make a writable file read-only */
1517                                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1518                                 attr.unixModeBits = scp->unixModeBits & ~0222;
1519                         }
1520                         else if ((scp->unixModeBits & 0222) == 0
1521                                  && (attribute & 1) == 0) {
1522                                 /* make a read-only file writable */
1523                                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1524                                 attr.unixModeBits = scp->unixModeBits | 0222;
1525                         }
1526                 }
1527                 lock_ReleaseMutex(&scp->mx);
1528
1529                 /* call setattr */
1530                 if (attr.mask)
1531                         code = cm_SetAttr(scp, &attr, userp, &req);
1532                 else
1533                         code = 0;
1534         }
1535         else if (infoLevel == 0x103 || infoLevel == 0x104) {
1536                 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1537                 cm_attr_t attr;
1538
1539                 attr.mask = CM_ATTRMASK_LENGTH;
1540                 attr.length.LowPart = size.LowPart;
1541                 attr.length.HighPart = size.HighPart;
1542                 code = cm_SetAttr(scp, &attr, userp, &req);
1543         }
1544         else if (infoLevel == 0x102) {
1545                 if (*((char *)(p->datap))) {
1546                         code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1547                                                 &req);
1548                         if (code == 0)
1549                                 fidp->flags |= SMB_FID_DELONCLOSE;
1550                 }
1551                 else {
1552                         code = 0;
1553                         fidp->flags &= ~SMB_FID_DELONCLOSE;
1554                 }
1555         }
1556 done:
1557         cm_ReleaseUser(userp);
1558         smb_ReleaseFID(fidp);
1559         if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1560         else smb_SendTran2Error(vcp, p, op, code);
1561         smb_FreeTran2Packet(outp);
1562
1563         return 0;
1564 }
1565
1566 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1567 {
1568         return CM_ERROR_BADOP;
1569 }
1570
1571 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1572 {
1573         return CM_ERROR_BADOP;
1574 }
1575
1576 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1577 {
1578         return CM_ERROR_BADOP;
1579 }
1580
1581 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1582 {
1583         return CM_ERROR_BADOP;
1584 }
1585
1586 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1587 {
1588         return CM_ERROR_BADOP;
1589 }
1590
1591 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1592         smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1593         cm_req_t *reqp)
1594 {
1595         long code;
1596         cm_scache_t *scp;
1597         cm_scache_t *targetScp;                 /* target if scp is a symlink */
1598         char *dptr;
1599         long dosTime;
1600         FILETIME ft;
1601         int shortTemp;
1602         unsigned short attr;
1603         unsigned long lattr;
1604         smb_dirListPatch_t *patchp;
1605         smb_dirListPatch_t *npatchp;
1606         
1607         for(patchp = *dirPatchespp; patchp; patchp =
1608                 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1609                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1610                 if (code) continue;
1611                 lock_ObtainMutex(&scp->mx);
1612                 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1613                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1614                 if (code) {
1615                         lock_ReleaseMutex(&scp->mx);
1616                         cm_ReleaseSCache(scp);
1617                         continue;
1618                 }
1619                 
1620                 /* now watch for a symlink */
1621                 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1622                         lock_ReleaseMutex(&scp->mx);
1623                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp,
1624                                                   reqp);
1625                         if (code == 0) {
1626                                 /* we have a more accurate file to use (the
1627                                  * target of the symbolic link).  Otherwise,
1628                                  * we'll just use the symlink anyway.
1629                                  */
1630                                 osi_Log2(afsd_logp, "symlink vp %x to vp %x",
1631                                          scp, targetScp);
1632                                 cm_ReleaseSCache(scp);
1633                                 scp = targetScp;
1634                         }
1635                         lock_ObtainMutex(&scp->mx);
1636                 }
1637
1638                 dptr = patchp->dptr;
1639
1640                 if (infoLevel >= 0x101) {
1641                         /* get filetime */
1642                         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1643
1644                         /* copy to Creation Time */
1645                         *((FILETIME *)dptr) = ft;
1646                         dptr += 8;
1647
1648                         /* copy to Last Access Time */
1649                         *((FILETIME *)dptr) = ft;
1650                         dptr += 8;
1651
1652                         /* copy to Last Write Time */
1653                         *((FILETIME *)dptr) = ft;
1654                         dptr += 8;
1655
1656                         /* copy to Change Time */
1657                         *((FILETIME *)dptr) = ft;
1658                         dptr += 8;
1659
1660                         /* Use length for both file length and alloc length */
1661                         *((LARGE_INTEGER *)dptr) = scp->length;
1662                         dptr += 8;
1663                         *((LARGE_INTEGER *)dptr) = scp->length;
1664                         dptr += 8;
1665
1666                         /* Copy attributes */
1667                         lattr = smb_ExtAttributes(scp);
1668             /* merge in hidden (dot file) attribute */
1669                         if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1670                                 lattr |= SMB_ATTR_HIDDEN;
1671                         *((u_long *)dptr) = lattr;
1672                         dptr += 4;
1673                 }
1674                 else {
1675                         /* get dos time */
1676                         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1677
1678                         /* and copy out date */
1679                         shortTemp = (dosTime>>16) & 0xffff;
1680                         *((u_short *)dptr) = shortTemp;
1681                         dptr += 2;
1682
1683                         /* copy out creation time */
1684                         shortTemp = dosTime & 0xffff;
1685                         *((u_short *)dptr) = shortTemp;
1686                         dptr += 2;
1687
1688                         /* and copy out date */
1689                         shortTemp = (dosTime>>16) & 0xffff;
1690                         *((u_short *)dptr) = shortTemp;
1691                         dptr += 2;
1692                         
1693                         /* copy out access time */
1694                         shortTemp = dosTime & 0xffff;
1695                         *((u_short *)dptr) = shortTemp;
1696                         dptr += 2;
1697
1698                         /* and copy out date */
1699                         shortTemp = (dosTime>>16) & 0xffff;
1700                         *((u_short *)dptr) = shortTemp;
1701                         dptr += 2;
1702                         
1703                         /* copy out mod time */
1704                         shortTemp = dosTime & 0xffff;
1705                         *((u_short *)dptr) = shortTemp;
1706                         dptr += 2;
1707
1708                         /* copy out file length and alloc length,
1709                          * using the same for both
1710                          */
1711                         *((u_long *)dptr) = scp->length.LowPart;
1712                         dptr += 4;
1713                         *((u_long *)dptr) = scp->length.LowPart;
1714                         dptr += 4;
1715
1716                         /* finally copy out attributes as short */
1717                         attr = smb_Attributes(scp);
1718             /* merge in hidden (dot file) attribute */
1719             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1720                 attr |= SMB_ATTR_HIDDEN;
1721                         *dptr++ = attr & 0xff;
1722                         *dptr++ = (attr >> 8) & 0xff;
1723                 }
1724
1725                 lock_ReleaseMutex(&scp->mx);
1726                 cm_ReleaseSCache(scp);
1727         }
1728         
1729         /* now free the patches */
1730         for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1731                 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1732                 free(patchp);
1733         }
1734         
1735         /* and mark the list as empty */
1736         *dirPatchespp = NULL;
1737
1738         return code;
1739 }
1740
1741 /* do a case-folding search of the star name mask with the name in namep.
1742  * Return 1 if we match, otherwise 0.
1743  */
1744 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1745 {
1746         unsigned char tcp1, tcp2;       /* Pattern characters */
1747         unsigned char tcn1;             /* Name characters */
1748         int sawDot = 0, sawStar = 0, req8dot3 = 0;
1749         char *starNamep, *starMaskp;
1750         static char nullCharp[] = {0};
1751
1752         /* make sure we only match 8.3 names, if requested */
1753     req8dot3 = (flags & CM_FLAG_8DOT3);
1754         if (req8dot3 && !cm_Is8Dot3(namep)) 
1755         return 0;
1756
1757         /* loop */
1758         while (1) {
1759                 /* Next pattern character */
1760                 tcp1 = *maskp++;
1761
1762                 /* Next name character */
1763                 tcn1 = *namep;
1764
1765                 if (tcp1 == 0) {
1766                         /* 0 - end of pattern */
1767                         if (tcn1 == 0)
1768                                 return 1;
1769                         else
1770                                 return 0;
1771                 }
1772                 else if (tcp1 == '.' || tcp1 == '"') {
1773                         if (sawDot) {
1774                                 if (tcn1 == '.') {
1775                                         namep++;
1776                                         continue;
1777                                 } else
1778                                         return 0;
1779                         }
1780                         else {
1781                                 /*
1782                                  * first dot in pattern;
1783                                  * must match dot or end of name
1784                                  */
1785                                 sawDot = 1;
1786                                 if (tcn1 == 0)
1787                                         continue;
1788                                 else if (tcn1 == '.') {
1789                                         sawStar = 0;
1790                                         namep++;
1791                                         continue;
1792                                 }
1793                                 else
1794                                         return 0;
1795                         }
1796                 }
1797                 else if (tcp1 == '?') {
1798                         if (tcn1 == 0 || tcn1 == '.')
1799                                 return 0;
1800                         namep++;
1801                         continue;
1802                 }
1803                 else if (tcp1 == '>') {
1804                         if (tcn1 != 0 && tcn1 != '.')
1805                                 namep++;
1806                         continue;
1807                 }
1808                 else if (tcp1 == '*' || tcp1 == '<') {
1809                         tcp2 = *maskp++;
1810                         if (tcp2 == 0)
1811                                 return 1;
1812                         else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
1813                                 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
1814                                         tcn1 = *++namep;
1815                                 if (tcn1 == 0) {
1816                                         if (sawDot)
1817                                                 return 0;
1818                                         else
1819                                                 continue;
1820                                 }
1821                                 else {
1822                                         namep++;
1823                                         continue;
1824                                 }
1825                         }
1826                         else {
1827                                 /*
1828                                  * pattern character after '*' is not null or
1829                                  * period.  If it is '?' or '>', we are not
1830                                  * going to understand it.  If it is '*' or
1831                                  * '<', we are going to skip over it.  None of
1832                                  * these are likely, I hope.
1833                                  */
1834                                 /* skip over '*' and '<' */
1835                                 while (tcp2 == '*' || tcp2 == '<')
1836                                         tcp2 = *maskp++;
1837
1838                                 /* skip over characters that don't match tcp2 */
1839                                 while (req8dot3 && tcn1 != '.' && tcn1 != 0
1840                                         && cm_foldUpper[tcn1] != cm_foldUpper[tcp2])
1841                                         tcn1 = *++namep;
1842
1843                                 /* No match */
1844                                 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
1845                                         return 0;
1846
1847                                 /* Remember where we are */
1848                                 sawStar = 1;
1849                                 starMaskp = maskp;
1850                                 starNamep = namep;
1851
1852                                 namep++;
1853                                 continue;
1854                         }
1855                 }
1856                 else {
1857                         /* tcp1 is not a wildcard */
1858                         if (cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) {
1859                                 /* they match */
1860                                 namep++;
1861                                 continue;
1862                         }
1863                         /* if trying to match a star pattern, go back */
1864                         if (sawStar) {
1865                                 maskp = starMaskp - 2;
1866                                 namep = starNamep + 1;
1867                                 sawStar = 0;
1868                                 continue;
1869                         }
1870                         /* that's all */
1871                         return 0;
1872                 }
1873         }
1874 }
1875
1876 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1877 {
1878         int attribute;
1879         long nextCookie;
1880         char *tp;
1881         long code;
1882         char *pathp;
1883         cm_dirEntry_t *dep;
1884         int maxCount;
1885         smb_dirListPatch_t *dirListPatchesp;
1886         smb_dirListPatch_t *curPatchp;
1887         cm_buf_t *bufferp;
1888         long temp;
1889         long orbytes;                   /* # of bytes in this output record */
1890         long ohbytes;                   /* # of bytes, except file name */
1891         long onbytes;                   /* # of bytes in name, incl. term. null */
1892         osi_hyper_t dirLength;
1893         osi_hyper_t bufferOffset;
1894         osi_hyper_t curOffset;
1895         osi_hyper_t thyper;
1896         smb_dirSearch_t *dsp;
1897         cm_scache_t *scp;
1898         long entryInDir;
1899         long entryInBuffer;
1900         cm_pageHeader_t *pageHeaderp;
1901         cm_user_t *userp = NULL;
1902         int slotInPage;
1903         int returnedNames;
1904         long nextEntryCookie;
1905         int numDirChunks;               /* # of 32 byte dir chunks in this entry */
1906         char *op;                       /* output data ptr */
1907         char *origOp;                   /* original value of op */
1908         cm_space_t *spacep;             /* for pathname buffer */
1909         long maxReturnData;             /* max # of return data */
1910         long maxReturnParms;            /* max # of return parms */
1911         long bytesInBuffer;             /* # data bytes in the output buffer */
1912         int starPattern;
1913         char *maskp;                    /* mask part of path */
1914         int infoLevel;
1915         int searchFlags;
1916         int eos;
1917         smb_tran2Packet_t *outp;        /* response packet */
1918         char *tidPathp;
1919         int align;
1920         char shortName[13];             /* 8.3 name if needed */
1921         int NeedShortName;
1922         char *shortNameEnd;
1923         int fileType;
1924         cm_fid_t fid;
1925         
1926         cm_req_t req;
1927
1928         cm_InitReq(&req);
1929
1930         eos = 0;
1931         if (p->opcode == 1) {
1932                 /* find first; obtain basic parameters from request */
1933                 attribute = p->parmsp[0];
1934                 maxCount = p->parmsp[1];
1935                 infoLevel = p->parmsp[3];
1936                 searchFlags = p->parmsp[2];
1937                 dsp = smb_NewDirSearch(1);
1938                 dsp->attribute = attribute;
1939                 pathp = ((char *) p->parmsp) + 12;      /* points to path */
1940                 nextCookie = 0;
1941                 maskp = strrchr(pathp, '\\');
1942                 if (maskp == NULL) maskp = pathp;
1943                 else maskp++;   /* skip over backslash */
1944                 strcpy(dsp->mask, maskp);       /* and save mask */
1945                 /* track if this is likely to match a lot of entries */
1946                 starPattern = smb_V3IsStarMask(maskp);
1947         }
1948         else {
1949                 osi_assert(p->opcode == 2);
1950                 /* find next; obtain basic parameters from request or open dir file */
1951                 dsp = smb_FindDirSearch(p->parmsp[0]);
1952                 if (!dsp) return CM_ERROR_BADFD;
1953                 attribute = dsp->attribute;
1954                 maxCount = p->parmsp[1];
1955                 infoLevel = p->parmsp[2];
1956                 searchFlags = p->parmsp[5];
1957                 pathp = NULL;
1958                 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
1959                 maskp = dsp->mask;
1960                 starPattern = 1;        /* assume, since required a Find Next */
1961         }
1962
1963         osi_Log4(afsd_logp,
1964                  "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
1965                  attribute, infoLevel, maxCount, searchFlags);
1966
1967         osi_Log2(afsd_logp, "...T2 search op %d, nextCookie 0x%x",
1968                  p->opcode, nextCookie);
1969
1970         if (infoLevel >= 0x101)
1971                 searchFlags &= ~4;      /* no resume keys */
1972
1973         dirListPatchesp = NULL;
1974
1975         maxReturnData = p->maxReturnData;
1976         if (p->opcode == 1)     /* find first */
1977                 maxReturnParms = 10;    /* bytes */
1978         else
1979                 maxReturnParms = 8;     /* bytes */
1980
1981 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
1982         if (maxReturnData > 6000) maxReturnData = 6000;
1983 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
1984
1985         outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
1986                                           maxReturnData);
1987
1988         osi_Log1(afsd_logp, "T2 receive search dir %s",
1989                         osi_LogSaveString(afsd_logp, pathp));
1990         
1991         /* bail out if request looks bad */
1992     if (p->opcode == 1 && !pathp) {
1993         smb_ReleaseDirSearch(dsp);
1994         smb_FreeTran2Packet(outp);
1995         return CM_ERROR_BADSMB;
1996     }
1997         
1998         osi_Log2(afsd_logp, "T2 dir search cookie 0x%x, connection %d",
1999                 nextCookie, dsp->cookie);
2000
2001         userp = smb_GetTran2User(vcp, p);
2002     if (!userp) {
2003         osi_Log1(afsd_logp, "T2 dir search unable to resolve user [%d]", p->uid);
2004         smb_ReleaseDirSearch(dsp);
2005         smb_FreeTran2Packet(outp);
2006         return CM_ERROR_BADSMB;
2007     }
2008
2009         /* try to get the vnode for the path name next */
2010         lock_ObtainMutex(&dsp->mx);
2011         if (dsp->scp) {
2012                 scp = dsp->scp;
2013                 cm_HoldSCache(scp);
2014                 code = 0;
2015         }
2016         else {
2017                 spacep = cm_GetSpace();
2018                 smb_StripLastComponent(spacep->data, NULL, pathp);
2019                 lock_ReleaseMutex(&dsp->mx);
2020
2021                 tidPathp = smb_GetTIDPath(vcp, p->tid);
2022                 code = cm_NameI(cm_rootSCachep, spacep->data,
2023                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2024                                 userp, tidPathp, &req, &scp);
2025                 cm_FreeSpace(spacep);
2026
2027                 lock_ObtainMutex(&dsp->mx);
2028                 if (code == 0) {
2029                         if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2030                         dsp->scp = scp;
2031                         /* we need one hold for the entry we just stored into,
2032                          * and one for our own processing.  When we're done
2033                          * with this function, we'll drop the one for our own
2034                          * processing.  We held it once from the namei call,
2035                          * and so we do another hold now.
2036                          */
2037                         cm_HoldSCache(scp);
2038                         lock_ObtainMutex(&scp->mx);
2039                         if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2040                             && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2041                                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2042                                 dsp->flags |= SMB_DIRSEARCH_BULKST;
2043                         }
2044                         lock_ReleaseMutex(&scp->mx);
2045                 }
2046         }
2047         lock_ReleaseMutex(&dsp->mx);
2048         if (code) {
2049                 cm_ReleaseUser(userp);
2050                 smb_FreeTran2Packet(outp);
2051                 smb_DeleteDirSearch(dsp);
2052                 smb_ReleaseDirSearch(dsp);
2053                 return code;
2054         }
2055
2056         /* get the directory size */
2057         lock_ObtainMutex(&scp->mx);
2058         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2059                 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2060         if (code) {
2061                 lock_ReleaseMutex(&scp->mx);
2062                 cm_ReleaseSCache(scp);
2063                 cm_ReleaseUser(userp);
2064                 smb_FreeTran2Packet(outp);
2065                 smb_DeleteDirSearch(dsp);
2066                 smb_ReleaseDirSearch(dsp);
2067                 return code;
2068         }
2069         
2070         dirLength = scp->length;
2071         bufferp = NULL;
2072         bufferOffset.LowPart = bufferOffset.HighPart = 0;
2073         curOffset.HighPart = 0;
2074         curOffset.LowPart = nextCookie;
2075         origOp = outp->datap;
2076
2077         code = 0;
2078         returnedNames = 0;
2079         bytesInBuffer = 0;
2080         while (1) {
2081                 op = origOp;
2082                 if (searchFlags & 4)
2083                         /* skip over resume key */
2084                         op += 4;
2085
2086                 /* make sure that curOffset.LowPart doesn't point to the first
2087                  * 32 bytes in the 2nd through last dir page, and that it doesn't
2088                  * point at the first 13 32-byte chunks in the first dir page,
2089                  * since those are dir and page headers, and don't contain useful
2090                  * information.
2091                  */
2092                 temp = curOffset.LowPart & (2048-1);
2093                 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2094                         /* we're in the first page */
2095                         if (temp < 13*32) temp = 13*32;
2096                 }
2097                 else {
2098                         /* we're in a later dir page */
2099                         if (temp < 32) temp = 32;
2100                 }
2101                 
2102                 /* make sure the low order 5 bits are zero */
2103                 temp &= ~(32-1);
2104                 
2105                 /* now put temp bits back ito curOffset.LowPart */
2106                 curOffset.LowPart &= ~(2048-1);
2107                 curOffset.LowPart |= temp;
2108
2109             /* check if we've passed the dir's EOF */
2110             if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2111                 eos = 1;
2112                 break;
2113             }
2114
2115             /* check if we've returned all the names that will fit in the
2116              * response packet; we check return count as well as the number
2117              * of bytes requested.  We check the # of bytes after we find
2118              * the dir entry, since we'll need to check its size.
2119              */
2120             if (returnedNames >= maxCount) {
2121                 break;
2122             }
2123                 
2124             /* see if we can use the bufferp we have now; compute in which
2125              * page the current offset would be, and check whether that's
2126              * the offset of the buffer we have.  If not, get the buffer.
2127              */
2128             thyper.HighPart = curOffset.HighPart;
2129             thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2130             if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2131                         /* wrong buffer */
2132                 if (bufferp) {
2133                     buf_Release(bufferp);
2134                     bufferp = NULL;
2135                         }   
2136                         lock_ReleaseMutex(&scp->mx);
2137                         lock_ObtainRead(&scp->bufCreateLock);
2138                         code = buf_Get(scp, &thyper, &bufferp);
2139                         lock_ReleaseRead(&scp->bufCreateLock);
2140
2141                         /* now, if we're doing a star match, do bulk fetching
2142                          * of all of the status info for files in the dir.
2143                          */
2144                         if (starPattern) {
2145                                 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2146                                                           infoLevel, userp,
2147                                                           &req);
2148                                 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2149                                     && LargeIntegerGreaterThanOrEqualTo(
2150                                                 thyper, scp->bulkStatProgress)) {
2151                                         /* Don't bulk stat if risking timeout */
2152                                         int now = GetCurrentTime();
2153                                         if (now - req.startTime > 5000) {
2154                                                 scp->bulkStatProgress = thyper;
2155                                                 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2156                                                 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2157                                         } else
2158                                                 cm_TryBulkStat(scp, &thyper,
2159                                                                userp, &req);
2160                                 }
2161                         }
2162
2163                         lock_ObtainMutex(&scp->mx);
2164                         if (code) break;
2165                         bufferOffset = thyper;
2166
2167                         /* now get the data in the cache */
2168                         while (1) {
2169                                 code = cm_SyncOp(scp, bufferp, userp, &req,
2170                                         PRSFS_LOOKUP,
2171                                         CM_SCACHESYNC_NEEDCALLBACK
2172                                         | CM_SCACHESYNC_READ);
2173                                 if (code) break;
2174                                 
2175                                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2176                                 
2177                                 /* otherwise, load the buffer and try again */
2178                                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2179                                                     &req);
2180                                 if (code) break;
2181                         }
2182                         if (code) {
2183                                 buf_Release(bufferp);
2184                                 bufferp = NULL;
2185                                 break;
2186                         }
2187                 }       /* if (wrong buffer) ... */
2188                 
2189                 /* now we have the buffer containing the entry we're interested
2190                  * in; copy it out if it represents a non-deleted entry.
2191                  */
2192                 entryInDir = curOffset.LowPart & (2048-1);
2193                 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2194
2195                 /* page header will help tell us which entries are free.  Page
2196                  * header can change more often than once per buffer, since
2197                  * AFS 3 dir page size may be less than (but not more than)
2198                  * a buffer package buffer.
2199                  */
2200                 /* only look intra-buffer */
2201                 temp = curOffset.LowPart & (buf_bufferSize - 1);
2202                 temp &= ~(2048 - 1);    /* turn off intra-page bits */
2203                 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2204
2205                 /* now determine which entry we're looking at in the page.
2206                  * If it is free (there's a free bitmap at the start of the
2207                  * dir), we should skip these 32 bytes.
2208                  */
2209                 slotInPage = (entryInDir & 0x7e0) >> 5;
2210                 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2211                         & (1 << (slotInPage & 0x7)))) {
2212                         /* this entry is free */
2213                         numDirChunks = 1;       /* only skip this guy */
2214                         goto nextEntry;
2215                 }
2216
2217                 tp = bufferp->datap + entryInBuffer;
2218                 dep = (cm_dirEntry_t *) tp;     /* now points to AFS3 dir entry */
2219
2220                 /* while we're here, compute the next entry's location, too,
2221                  * since we'll need it when writing out the cookie into the dir
2222                  * listing stream.
2223                  *
2224                  * XXXX Probably should do more sanity checking.
2225                  */
2226                 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2227                 
2228                 /* compute offset of cookie representing next entry */
2229                 nextEntryCookie = curOffset.LowPart
2230                                     + (CM_DIR_CHUNKSIZE * numDirChunks);
2231
2232                 /* Need 8.3 name? */
2233                 NeedShortName = 0;
2234                 if (infoLevel == 0x104
2235                     && dep->fid.vnode != 0
2236                     && !cm_Is8Dot3(dep->name)) {
2237                         cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2238                         NeedShortName = 1;
2239                 }
2240
2241                 if (dep->fid.vnode != 0
2242                     && (smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)
2243                         || (NeedShortName
2244                             && smb_V3MatchMask(shortName, maskp,
2245                                                 CM_FLAG_CASEFOLD)))) {
2246
2247                         /* Eliminate entries that don't match requested
2248                            attributes */
2249                     if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && 
2250                         smb_IsDotFile(dep->name))
2251                         goto nextEntry; /* no hidden files */
2252                     
2253                     if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
2254                     {
2255                             /* We have already done the cm_TryBulkStat above */
2256                             fid.cell = scp->fid.cell;
2257                             fid.volume = scp->fid.volume;
2258                             fid.vnode = ntohl(dep->fid.vnode);
2259                             fid.unique = ntohl(dep->fid.unique);
2260                             fileType = cm_FindFileType(&fid);
2261                             /*osi_Log2(afsd_logp, "smb_ReceiveTran2SearchDir: file %s "
2262                               "has filetype %d", dep->name,
2263                               fileType);*/
2264                             if (fileType == CM_SCACHETYPE_DIRECTORY)
2265                               goto nextEntry;
2266                         }
2267
2268                         /* finally check if this name will fit */
2269
2270                         /* standard dir entry stuff */
2271                         if (infoLevel < 0x101)
2272                                 ohbytes = 23;   /* pre-NT */
2273                         else if (infoLevel == 0x103)
2274                                 ohbytes = 12;   /* NT names only */
2275                         else
2276                                 ohbytes = 64;   /* NT */
2277
2278                         if (infoLevel == 0x104)
2279                                 ohbytes += 26;  /* Short name & length */
2280
2281                         if (searchFlags & 4) {
2282                                 ohbytes += 4;   /* if resume key required */
2283                         }
2284
2285                         if (infoLevel != 1
2286                             && infoLevel != 0x101
2287                             && infoLevel != 0x103)
2288                                 ohbytes += 4;   /* EASIZE */
2289
2290                         /* add header to name & term. null */
2291                         orbytes = onbytes + ohbytes + 1;
2292
2293                         /* now, we round up the record to a 4 byte alignment,
2294                          * and we make sure that we have enough room here for
2295                          * even the aligned version (so we don't have to worry
2296                          * about an * overflow when we pad things out below).
2297                          * That's the reason for the alignment arithmetic below.
2298                          */
2299                         if (infoLevel >= 0x101)
2300                                 align = (4 - (orbytes & 3)) & 3;
2301                         else
2302                                 align = 0;
2303                         if (orbytes + bytesInBuffer + align > maxReturnData)
2304                                 break;
2305
2306                         /* this is one of the entries to use: it is not deleted
2307                          * and it matches the star pattern we're looking for.
2308                          * Put out the name, preceded by its length.
2309                          */
2310                         /* First zero everything else */
2311                         memset(origOp, 0, ohbytes);
2312
2313                         if (infoLevel <= 0x101)
2314                                 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2315                         else if (infoLevel == 0x103)
2316                                 *((u_long *)(op + 8)) = onbytes;
2317                         else
2318                                 *((u_long *)(op + 60)) = onbytes;
2319                         strcpy(origOp+ohbytes, dep->name);
2320
2321                         /* Short name if requested and needed */
2322                         if (infoLevel == 0x104) {
2323                                 if (NeedShortName) {
2324                                         strcpy(op + 70, shortName);
2325                                         *(op + 68) = shortNameEnd - shortName;
2326                                 }
2327                         }
2328
2329                         /* now, adjust the # of entries copied */
2330                         returnedNames++;
2331
2332                         /* NextEntryOffset and FileIndex */
2333                         if (infoLevel >= 101) {
2334                                 int entryOffset = orbytes + align;
2335                                 *((u_long *)op) = entryOffset;
2336                                 *((u_long *)(op+4)) = nextEntryCookie;
2337                         }
2338
2339                         /* now we emit the attribute.  This is tricky, since
2340                          * we need to really stat the file to find out what
2341                          * type of entry we've got.  Right now, we're copying
2342                          * out data from * a buffer, while holding the scp
2343                          * locked, so it isn't really convenient to stat
2344                          * something now.  We'll put in a place holder
2345                          * now, and make a second pass before returning this
2346                          * to get the real attributes.  So, we just skip the
2347                          * data for now, and adjust it later.  We allocate a
2348                          * patch record to make it easy to find this point
2349                          * later.  The replay will happen at a time when it is
2350                          * safe to unlock the directory.
2351                          */
2352                         if (infoLevel != 0x103) {
2353                                 curPatchp = malloc(sizeof(*curPatchp));
2354                                 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2355                                          &curPatchp->q);
2356                                 curPatchp->dptr = op;
2357                                 if (infoLevel >= 0x101)
2358                                         curPatchp->dptr += 8;
2359
2360                 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
2361                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
2362                 }
2363                 else
2364                     curPatchp->flags = 0;
2365
2366                                 curPatchp->fid.cell = scp->fid.cell;
2367                                 curPatchp->fid.volume = scp->fid.volume;
2368                                 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2369                                 curPatchp->fid.unique = ntohl(dep->fid.unique);
2370
2371                                 /* temp */
2372                                 curPatchp->dep = dep;
2373                         }
2374
2375                         if (searchFlags & 4)
2376                                 /* put out resume key */
2377                                 *((u_long *)origOp) = nextEntryCookie;
2378
2379                         /* Adjust byte ptr and count */
2380                         origOp += orbytes;      /* skip entire record */
2381                         bytesInBuffer += orbytes;
2382
2383                         /* and pad the record out */
2384                         while (--align >= 0) {
2385                                 *origOp++ = 0;
2386                                 bytesInBuffer++;
2387                         }
2388                         
2389                 }       /* if we're including this name */
2390                 
2391 nextEntry:
2392                 /* and adjust curOffset to be where the new cookie is */
2393                 thyper.HighPart = 0;
2394                 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2395                 curOffset = LargeIntegerAdd(thyper, curOffset);
2396         }               /* while copying data for dir listing */
2397
2398         /* release the mutex */
2399         lock_ReleaseMutex(&scp->mx);
2400         if (bufferp) buf_Release(bufferp);
2401
2402         /* apply and free last set of patches; if not doing a star match, this
2403          * will be empty, but better safe (and freeing everything) than sorry.
2404          */
2405         smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2406                                   &req);
2407         
2408         /* now put out the final parameters */
2409         if (returnedNames == 0) eos = 1;
2410         if (p->opcode == 1) {
2411                 /* find first */
2412                 outp->parmsp[0] = (unsigned short) dsp->cookie;
2413                 outp->parmsp[1] = returnedNames;
2414                 outp->parmsp[2] = eos;
2415                 outp->parmsp[3] = 0;            /* nothing wrong with EAS */
2416                 outp->parmsp[4] = 0;    /* don't need last name to continue
2417                                          * search, cookie is enough.  Normally,
2418                                          * this is the offset of the file name
2419                                          * of the last entry returned.
2420                                          */
2421                 outp->totalParms = 10;  /* in bytes */
2422         }
2423         else {
2424                 /* find next */
2425                 outp->parmsp[0] = returnedNames;
2426                 outp->parmsp[1] = eos;
2427                 outp->parmsp[2] = 0;    /* EAS error */
2428                 outp->parmsp[3] = 0;    /* last name, as above */
2429                 outp->totalParms = 8;   /* in bytes */
2430         }
2431
2432         /* return # of bytes in the buffer */
2433         outp->totalData = bytesInBuffer;
2434
2435         osi_Log2(afsd_logp, "T2 search dir done, %d names, code %d",
2436                 returnedNames, code);
2437
2438         /* Return error code if unsuccessful on first request */
2439         if (code == 0 && p->opcode == 1 && returnedNames == 0)
2440                 code = CM_ERROR_NOSUCHFILE;
2441
2442         /* if we're supposed to close the search after this request, or if
2443          * we're supposed to close the search if we're done, and we're done,
2444          * or if something went wrong, close the search.
2445          */
2446         /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2447         if ((searchFlags & 1) || (returnedNames == 0) || ((searchFlags & 2) &&
2448                                                           eos) || code != 0)
2449             smb_DeleteDirSearch(dsp);
2450         if (code)
2451                 smb_SendTran2Error(vcp, p, opx, code);
2452         else {
2453                 smb_SendTran2Packet(vcp, outp, opx);
2454         }
2455         smb_FreeTran2Packet(outp);
2456     smb_ReleaseDirSearch(dsp);
2457     cm_ReleaseSCache(scp);
2458     cm_ReleaseUser(userp);
2459     return 0;
2460 }
2461
2462 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2463 {
2464     int dirHandle;
2465     smb_dirSearch_t *dsp;
2466
2467     dirHandle = smb_GetSMBParm(inp, 0);
2468         
2469     osi_Log1(afsd_logp, "SMB3 find close handle %d", dirHandle);
2470
2471     dsp = smb_FindDirSearch(dirHandle);
2472         
2473     if (!dsp)
2474                 return CM_ERROR_BADFD;
2475         
2476     /* otherwise, we have an FD to destroy */
2477     smb_DeleteDirSearch(dsp);
2478     smb_ReleaseDirSearch(dsp);
2479         
2480         /* and return results */
2481         smb_SetSMBDataLength(outp, 0);
2482
2483     return 0;
2484 }
2485
2486 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2487 {
2488         smb_SetSMBDataLength(outp, 0);
2489     return 0;
2490 }
2491
2492 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2493 {
2494         char *pathp;
2495     long code;
2496         cm_space_t *spacep;
2497     int excl;
2498     cm_user_t *userp;
2499     cm_scache_t *dscp;          /* dir we're dealing with */
2500     cm_scache_t *scp;           /* file we're creating */
2501     cm_attr_t setAttr;
2502     int initialModeBits;
2503     smb_fid_t *fidp;
2504     int attributes;
2505     char *lastNamep;
2506     long dosTime;
2507     int openFun;
2508     int trunc;
2509     int openMode;
2510     int extraInfo;
2511     int openAction;
2512     int parmSlot;                       /* which parm we're dealing with */
2513         char *tidPathp;
2514         cm_req_t req;
2515
2516         cm_InitReq(&req);
2517
2518     scp = NULL;
2519         
2520         extraInfo = (smb_GetSMBParm(inp, 2) & 1);       /* return extra info */
2521         openFun = smb_GetSMBParm(inp, 8);       /* open function */
2522     excl = ((openFun & 3) == 0);
2523     trunc = ((openFun & 3) == 2);               /* truncate it */
2524         openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2525     openAction = 0;                     /* tracks what we did */
2526
2527     attributes = smb_GetSMBParm(inp, 5);
2528     dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2529
2530         /* compute initial mode bits based on read-only flag in attributes */
2531     initialModeBits = 0666;
2532     if (attributes & 1) initialModeBits &= ~0222;
2533         
2534     pathp = smb_GetSMBData(inp, NULL);
2535
2536         spacep = inp->spacep;
2537     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2538
2539         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2540                 /* special case magic file name for receiving IOCTL requests
2541          * (since IOCTL calls themselves aren't getting through).
2542          */
2543 #ifdef NOTSERVICE
2544         osi_Log0(afsd_logp, "IOCTL Open");
2545 #endif
2546
2547         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2548         smb_SetupIoctlFid(fidp, spacep);
2549
2550                 /* set inp->fid so that later read calls in same msg can find fid */
2551         inp->fid = fidp->fid;
2552         
2553         /* copy out remainder of the parms */
2554                 parmSlot = 2;
2555                 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2556                 if (extraInfo) {
2557             smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2558             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* mod time */
2559             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2560             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* len */
2561             smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2562             smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2563             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2564             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2565                 }   
2566                 /* and the final "always present" stuff */
2567         smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2568                 /* next write out the "unique" ID */
2569                 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2570                 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2571         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2572         smb_SetSMBDataLength(outp, 0);
2573
2574                 /* and clean up fid reference */
2575         smb_ReleaseFID(fidp);
2576         return 0;
2577     }
2578
2579 #ifdef DEBUG_VERBOSE
2580     {
2581         char *hexp, *asciip;
2582         asciip = (lastNamep ? lastNamep : pathp );
2583         hexp = osi_HexifyString(asciip);
2584         DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
2585         free(hexp);
2586     }
2587 #endif
2588     userp = smb_GetUser(vcp, inp);
2589
2590         dscp = NULL;
2591         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2592         code = cm_NameI(cm_rootSCachep, pathp,
2593                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2594                     userp, tidPathp, &req, &scp);
2595         if (code != 0) {
2596                 code = cm_NameI(cm_rootSCachep, spacep->data,
2597                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2598                         userp, tidPathp, &req, &dscp);
2599
2600         if (code) {
2601             cm_ReleaseUser(userp);
2602             return code;
2603         }
2604         
2605         /* otherwise, scp points to the parent directory.  Do a lookup,
2606          * and truncate the file if we find it, otherwise we create the
2607          * file.
2608          */
2609         if (!lastNamep) lastNamep = pathp;
2610         else lastNamep++;
2611         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2612                           &req, &scp);
2613         if (code && code != CM_ERROR_NOSUCHFILE) {
2614                         cm_ReleaseSCache(dscp);
2615             cm_ReleaseUser(userp);
2616             return code;
2617         }
2618         }
2619         
2620     /* if we get here, if code is 0, the file exists and is represented by
2621      * scp.  Otherwise, we have to create it.  The dir may be represented
2622      * by dscp, or we may have found the file directly.  If code is non-zero,
2623      * scp is NULL.
2624      */
2625         if (code == 0) {
2626         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2627         if (code) {
2628             if (dscp) cm_ReleaseSCache(dscp);
2629             cm_ReleaseSCache(scp);
2630             cm_ReleaseUser(userp);
2631             return code;
2632         }
2633
2634                 if (excl) {
2635                         /* oops, file shouldn't be there */
2636             if (dscp) cm_ReleaseSCache(dscp);
2637             cm_ReleaseSCache(scp);
2638             cm_ReleaseUser(userp);
2639             return CM_ERROR_EXISTS;
2640         }
2641
2642                 if (trunc) {
2643                         setAttr.mask = CM_ATTRMASK_LENGTH;
2644             setAttr.length.LowPart = 0;
2645             setAttr.length.HighPart = 0;
2646                         code = cm_SetAttr(scp, &setAttr, userp, &req);
2647             openAction = 3;     /* truncated existing file */
2648                 }
2649         else openAction = 1;    /* found existing file */
2650     }
2651         else if (!(openFun & 0x10)) {
2652                 /* don't create if not found */
2653         if (dscp) cm_ReleaseSCache(dscp);
2654         cm_ReleaseUser(userp);
2655         return CM_ERROR_NOSUCHFILE;
2656     }
2657     else {
2658                 osi_assert(dscp != NULL);
2659                 osi_Log1(afsd_logp, "smb_ReceiveV3OpenX creating file %s",
2660                  osi_LogSaveString(afsd_logp, lastNamep));
2661                 openAction = 2; /* created file */
2662                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2663                 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2664         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2665                          &req);
2666                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2667                         smb_NotifyChange(FILE_ACTION_ADDED,
2668                              FILE_NOTIFY_CHANGE_FILE_NAME,
2669                              dscp, lastNamep, NULL, TRUE);
2670         if (!excl && code == CM_ERROR_EXISTS) {
2671                         /* not an exclusive create, and someone else tried
2672                          * creating it already, then we open it anyway.  We
2673                          * don't bother retrying after this, since if this next
2674                          * fails, that means that the file was deleted after we
2675                          * started this call.
2676              */
2677             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2678                              userp, &req, &scp);
2679             if (code == 0) {
2680                 if (trunc) {
2681                                         setAttr.mask = CM_ATTRMASK_LENGTH;
2682                     setAttr.length.LowPart = 0;
2683                     setAttr.length.HighPart = 0;
2684                     code = cm_SetAttr(scp, &setAttr, userp, &req);
2685                 }   
2686                         }       /* lookup succeeded */
2687         }
2688     }
2689         
2690         /* we don't need this any longer */
2691         if (dscp) cm_ReleaseSCache(dscp);
2692
2693     if (code) {
2694                 /* something went wrong creating or truncating the file */
2695         if (scp) cm_ReleaseSCache(scp);
2696         cm_ReleaseUser(userp);
2697         return code;
2698     }
2699         
2700         /* make sure we're about to open a file */
2701         if (scp->fileType != CM_SCACHETYPE_FILE) {
2702                 cm_ReleaseSCache(scp);
2703                 cm_ReleaseUser(userp);
2704                 return CM_ERROR_ISDIR;
2705         }
2706
2707     /* now all we have to do is open the file itself */
2708     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2709     osi_assert(fidp);
2710         
2711         /* save a pointer to the vnode */
2712     fidp->scp = scp;
2713         
2714         /* compute open mode */
2715     if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2716     if (openMode == 1 || openMode == 2)
2717         fidp->flags |= SMB_FID_OPENWRITE;
2718
2719         smb_ReleaseFID(fidp);
2720         
2721         cm_Open(scp, 0, userp);
2722
2723         /* set inp->fid so that later read calls in same msg can find fid */
2724     inp->fid = fidp->fid;
2725         
2726     /* copy out remainder of the parms */
2727         parmSlot = 2;
2728         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2729         lock_ObtainMutex(&scp->mx);
2730         if (extraInfo) {
2731         smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2732                 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2733         smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2734         smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2735         smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2736         smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2737         smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2738         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2739         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2740         }
2741         /* and the final "always present" stuff */
2742     smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2743         /* next write out the "unique" ID */
2744         smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2745         smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2746     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2747         lock_ReleaseMutex(&scp->mx);
2748     smb_SetSMBDataLength(outp, 0);
2749
2750         osi_Log1(afsd_logp, "SMB OpenX opening fid %d", fidp->fid);
2751
2752     cm_ReleaseUser(userp);
2753     /* leave scp held since we put it in fidp->scp */
2754     return 0;
2755 }   
2756
2757 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2758 {
2759         cm_req_t req;
2760         cm_user_t *userp;
2761         unsigned short fid;
2762         smb_fid_t *fidp;
2763         cm_scache_t *scp;
2764         unsigned char LockType;
2765         unsigned short NumberOfUnlocks, NumberOfLocks;
2766         unsigned long Timeout;
2767         char *op;
2768         LARGE_INTEGER LOffset, LLength;
2769         smb_waitingLock_t *waitingLock;
2770         void *lockp;
2771         long code;
2772         int i;
2773
2774         cm_InitReq(&req);
2775
2776         fid = smb_GetSMBParm(inp, 2);
2777         fid = smb_ChainFID(fid, inp);
2778
2779         fidp = smb_FindFID(vcp, fid, 0);
2780         if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2781                 return CM_ERROR_BADFD;
2782         }
2783         /* set inp->fid so that later read calls in same msg can find fid */
2784     inp->fid = fid;
2785
2786         userp = smb_GetUser(vcp, inp);
2787
2788         scp = fidp->scp;
2789
2790         lock_ObtainMutex(&scp->mx);
2791         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2792                          CM_SCACHESYNC_NEEDCALLBACK
2793                          | CM_SCACHESYNC_GETSTATUS
2794                          | CM_SCACHESYNC_LOCK);
2795         if (code) goto doneSync;
2796
2797         LockType = smb_GetSMBParm(inp, 3) & 0xff;
2798         Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2799         NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2800         NumberOfLocks = smb_GetSMBParm(inp, 7);
2801
2802         op = smb_GetSMBData(inp, NULL);
2803
2804         for (i=0; i<NumberOfUnlocks; i++) {
2805                 if (LockType & 0x10) {
2806                         /* Large Files */
2807                         LOffset.HighPart = *((LONG *)(op + 4));
2808                         LOffset.LowPart = *((DWORD *)(op + 8));
2809                         LLength.HighPart = *((LONG *)(op + 12));
2810                         LLength.LowPart = *((DWORD *)(op + 16));
2811                         op += 20;
2812                 }
2813                 else {
2814                         /* Not Large Files */
2815                         LOffset.HighPart = 0;
2816                         LOffset.LowPart = *((DWORD *)(op + 2));
2817                         LLength.HighPart = 0;
2818                         LLength.LowPart = *((DWORD *)(op + 6));
2819                         op += 10;
2820                 }
2821                 if (LargeIntegerNotEqualToZero(LOffset))
2822                         continue;
2823                 /* Do not check length -- length check done in cm_Unlock */
2824
2825                 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2826                 if (code) goto done;
2827         }
2828
2829         for (i=0; i<NumberOfLocks; i++) {
2830                 if (LockType & 0x10) {
2831                         /* Large Files */
2832                         LOffset.HighPart = *((LONG *)(op + 4));
2833                         LOffset.LowPart = *((DWORD *)(op + 8));
2834                         LLength.HighPart = *((LONG *)(op + 12));
2835                         LLength.LowPart = *((DWORD *)(op + 16));
2836                         op += 20;
2837                 }
2838                 else {
2839                         /* Not Large Files */
2840                         LOffset.HighPart = 0;
2841                         LOffset.LowPart = *((DWORD *)(op + 2));
2842                         LLength.HighPart = 0;
2843                         LLength.LowPart = *((DWORD *)(op + 6));
2844                         op += 10;
2845                 }
2846                 if (LargeIntegerNotEqualToZero(LOffset))
2847                         continue;
2848                 if (LargeIntegerLessThan(LOffset, scp->length))
2849                         continue;
2850
2851                 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2852                                 userp, &req, &lockp);
2853                 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2854                         /* Put on waiting list */
2855                         waitingLock = malloc(sizeof(smb_waitingLock_t));
2856                         waitingLock->vcp = vcp;
2857                         waitingLock->inp = smb_CopyPacket(inp);
2858                         waitingLock->outp = smb_CopyPacket(outp);
2859                         waitingLock->timeRemaining = Timeout;
2860                         waitingLock->lockp = lockp;
2861                         lock_ObtainWrite(&smb_globalLock);
2862                         osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2863                                  &waitingLock->q);
2864                         osi_Wakeup((long) &smb_allWaitingLocks);
2865                         lock_ReleaseWrite(&smb_globalLock);
2866                         /* don't send reply immediately */
2867                         outp->flags |= SMB_PACKETFLAG_NOSEND;
2868                 }
2869                 if (code) break;
2870         }
2871
2872         if (code) {
2873                 /* release any locks acquired before the failure */
2874         }
2875         else
2876                 smb_SetSMBDataLength(outp, 0);
2877 done:
2878         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2879 doneSync:
2880         lock_ReleaseMutex(&scp->mx);
2881         cm_ReleaseUser(userp);
2882         smb_ReleaseFID(fidp);
2883
2884         return code;
2885 }
2886
2887 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2888 {
2889         unsigned short fid;
2890     smb_fid_t *fidp;
2891     cm_scache_t *scp;
2892     long code;
2893     long searchTime;
2894     cm_user_t *userp;
2895         cm_req_t req;
2896
2897         cm_InitReq(&req);
2898
2899     fid = smb_GetSMBParm(inp, 0);
2900     fid = smb_ChainFID(fid, inp);
2901         
2902     fidp = smb_FindFID(vcp, fid, 0);
2903     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2904                 return CM_ERROR_BADFD;
2905     }
2906         
2907     userp = smb_GetUser(vcp, inp);
2908         
2909     scp = fidp->scp;
2910         
2911     /* otherwise, stat the file */
2912         lock_ObtainMutex(&scp->mx);
2913     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2914                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2915         if (code) goto done;
2916
2917         /* decode times.  We need a search time, but the response to this
2918      * call provides the date first, not the time, as returned in the
2919      * searchTime variable.  So we take the high-order bits first.
2920      */
2921         smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2922     smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff);       /* ctime */
2923     smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2924     smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff);       /* atime */
2925     smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2926     smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff);       /* mtime */
2927     smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2928
2929     /* now handle file size and allocation size */
2930     smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff);              /* file size */
2931     smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2932     smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff);              /* alloc size */
2933     smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2934
2935         /* file attribute */
2936     smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2937         
2938     /* and finalize stuff */
2939     smb_SetSMBDataLength(outp, 0);
2940     code = 0;
2941
2942 done:
2943         lock_ReleaseMutex(&scp->mx);
2944         cm_ReleaseUser(userp);
2945         smb_ReleaseFID(fidp);
2946         return code;
2947 }
2948
2949 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2950 {
2951         unsigned short fid;
2952     smb_fid_t *fidp;
2953     cm_scache_t *scp;
2954     long code;
2955         long searchTime;
2956     long unixTime;
2957     cm_user_t *userp;
2958     cm_attr_t attrs;
2959         cm_req_t req;
2960
2961         cm_InitReq(&req);
2962
2963     fid = smb_GetSMBParm(inp, 0);
2964     fid = smb_ChainFID(fid, inp);
2965         
2966     fidp = smb_FindFID(vcp, fid, 0);
2967     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2968                 return CM_ERROR_BADFD;
2969     }
2970         
2971     userp = smb_GetUser(vcp, inp);
2972         
2973     scp = fidp->scp;
2974         
2975         /* now prepare to call cm_setattr.  This message only sets various times,
2976      * and AFS only implements mtime, and we'll set the mtime if that's
2977      * requested.  The others we'll ignore.
2978      */
2979         searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
2980         
2981     if (searchTime != 0) {
2982                 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
2983
2984         if ( unixTime != -1 ) {
2985             attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
2986             attrs.clientModTime = unixTime;
2987             code = cm_SetAttr(scp, &attrs, userp, &req);
2988
2989             osi_Log1(afsd_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
2990         } else {
2991             osi_Log1(afsd_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
2992         }
2993     }
2994     else code = 0;
2995
2996         cm_ReleaseUser(userp);
2997         smb_ReleaseFID(fidp);
2998         return code;
2999 }
3000
3001
3002 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3003 {
3004         osi_hyper_t offset;
3005     long count, finalCount;
3006     unsigned short fd;
3007     smb_fid_t *fidp;
3008     long code;
3009     cm_user_t *userp;
3010     char *op;
3011         
3012     fd = smb_GetSMBParm(inp, 2);
3013     count = smb_GetSMBParm(inp, 5);
3014     offset.HighPart = 0;        /* too bad */
3015     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
3016
3017     osi_Log3(afsd_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
3018              fd, offset.LowPart, count);
3019         
3020         fd = smb_ChainFID(fd, inp);
3021     fidp = smb_FindFID(vcp, fd, 0);
3022     if (!fidp) {
3023                 return CM_ERROR_BADFD;
3024     }
3025         /* set inp->fid so that later read calls in same msg can find fid */
3026     inp->fid = fd;
3027
3028     if (fidp->flags & SMB_FID_IOCTL) {
3029                 return smb_IoctlV3Read(fidp, vcp, inp, outp);
3030     }
3031         
3032         userp = smb_GetUser(vcp, inp);
3033
3034         /* 0 and 1 are reserved for request chaining, were setup by our caller,
3035      * and will be further filled in after we return.
3036      */
3037     smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
3038     smb_SetSMBParm(outp, 3, 0); /* resvd */
3039     smb_SetSMBParm(outp, 4, 0); /* resvd */
3040         smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
3041     /* fill in #6 when we have all the parameters' space reserved */
3042     smb_SetSMBParm(outp, 7, 0); /* resv'd */
3043     smb_SetSMBParm(outp, 8, 0); /* resv'd */
3044     smb_SetSMBParm(outp, 9, 0); /* resv'd */
3045     smb_SetSMBParm(outp, 10, 0);        /* resv'd */
3046         smb_SetSMBParm(outp, 11, 0);    /* reserved */
3047
3048         /* get op ptr after putting in the parms, since otherwise we don't
3049      * know where the data really is.
3050      */
3051     op = smb_GetSMBData(outp, NULL);
3052         
3053     /* now fill in offset from start of SMB header to first data byte (to op) */
3054     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
3055
3056         /* set the packet data length the count of the # of bytes */
3057     smb_SetSMBDataLength(outp, count);
3058
3059 #ifndef DJGPP
3060         code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
3061 #else /* DJGPP */
3062         code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
3063 #endif /* !DJGPP */
3064
3065         /* fix some things up */
3066         smb_SetSMBParm(outp, 5, finalCount);
3067         smb_SetSMBDataLength(outp, finalCount);
3068
3069     smb_ReleaseFID(fidp);
3070
3071     cm_ReleaseUser(userp);
3072     return code;
3073 }   
3074         
3075 /*
3076  * Values for createDisp, copied from NTDDK.H
3077  *
3078  *  FILE_SUPERSEDE      0       (???)
3079  *  FILE_OPEN           1       (open)
3080  *  FILE_CREATE         2       (exclusive)
3081  *  FILE_OPEN_IF        3       (non-exclusive)
3082  *  FILE_OVERWRITE      4       (open & truncate, but do not create)
3083  *  FILE_OVERWRITE_IF   5       (open & truncate, or create)
3084  */
3085
3086 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3087 {
3088         char *pathp, *realPathp;
3089         long code;
3090         cm_space_t *spacep;
3091         cm_user_t *userp;
3092         cm_scache_t *dscp;              /* parent dir */
3093         cm_scache_t *scp;               /* file to create or open */
3094         cm_attr_t setAttr;
3095         char *lastNamep;
3096     char *treeStartp;
3097         unsigned short nameLength;
3098         unsigned int flags;
3099         unsigned int requestOpLock;
3100         unsigned int requestBatchOpLock;
3101         unsigned int mustBeDir;
3102     unsigned int treeCreate;
3103         int realDirFlag;
3104         unsigned int desiredAccess;
3105         unsigned int extAttributes;
3106         unsigned int createDisp;
3107         unsigned int createOptions;
3108         int initialModeBits;
3109         unsigned short baseFid;
3110         smb_fid_t *baseFidp;
3111         smb_fid_t *fidp;
3112         cm_scache_t *baseDirp;
3113         unsigned short openAction;
3114         int parmSlot;
3115         long fidflags;
3116         FILETIME ft;
3117         LARGE_INTEGER sz;
3118         char *tidPathp;
3119         BOOL foundscp;
3120         cm_req_t req;
3121
3122         cm_InitReq(&req);
3123
3124     treeCreate = FALSE;
3125         foundscp = FALSE;
3126         scp = NULL;
3127
3128         nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3129         flags = smb_GetSMBOffsetParm(inp, 3, 1)
3130                   | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3131         requestOpLock = flags & 0x02;
3132         requestBatchOpLock = flags & 0x04;
3133         mustBeDir = flags & 0x08;
3134
3135         /*
3136          * Why all of a sudden 32-bit FID?
3137          * We will reject all bits higher than 16.
3138          */
3139         if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3140                 return CM_ERROR_INVAL;
3141         baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3142         desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3143                           | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3144         extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3145                           | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3146         createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3147                         | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3148         createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3149                           | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3150
3151         /* mustBeDir is never set; createOptions directory bit seems to be
3152          * more important
3153          */
3154         if (createOptions & 1)
3155                 realDirFlag = 1;
3156         else if (createOptions & 0x40)
3157                 realDirFlag = 0;
3158         else
3159                 realDirFlag = -1;
3160
3161         /*
3162          * compute initial mode bits based on read-only flag in
3163          * extended attributes
3164          */
3165         initialModeBits = 0666;
3166         if (extAttributes & 1) initialModeBits &= ~0222;
3167
3168         pathp = smb_GetSMBData(inp, NULL);
3169         /* Sometimes path is not null-terminated, so we make a copy. */
3170         realPathp = malloc(nameLength+1);
3171         memcpy(realPathp, pathp, nameLength);
3172         realPathp[nameLength] = 0;
3173
3174         spacep = inp->spacep;
3175         smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3176
3177     osi_Log1(afsd_logp,"NTCreateX for [%s]",osi_LogSaveString(afsd_logp,realPathp));
3178     osi_Log4(afsd_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
3179
3180         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3181                 /* special case magic file name for receiving IOCTL requests
3182                  * (since IOCTL calls themselves aren't getting through).
3183                  */
3184                 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3185                 smb_SetupIoctlFid(fidp, spacep);
3186
3187                 /* set inp->fid so that later read calls in same msg can find fid */
3188                 inp->fid = fidp->fid;
3189
3190                 /* out parms */
3191                 parmSlot = 2;
3192                 smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
3193                 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3194                 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3195                 /* times */
3196                 memset(&ft, 0, sizeof(ft));
3197                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3198                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3199                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3200                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3201                 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3202                 sz.HighPart = 0x7fff; sz.LowPart = 0;
3203                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3204                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3205                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
3206                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
3207                 smb_SetSMBParmByte(outp, parmSlot, 0);  /* is a dir? */
3208                 smb_SetSMBDataLength(outp, 0);
3209
3210                 /* clean up fid reference */
3211                 smb_ReleaseFID(fidp);
3212                 free(realPathp);
3213                 return 0;
3214         }
3215
3216 #ifdef DEBUG_VERBOSE
3217     {
3218         char *hexp, *asciip;
3219         asciip = (lastNamep? lastNamep : realPathp);
3220         hexp = osi_HexifyString( asciip );
3221         DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
3222         free(hexp);
3223     }
3224 #endif
3225     userp = smb_GetUser(vcp, inp);
3226     if (!userp) {
3227         osi_Log1(afsd_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
3228         free(realPathp);
3229         return CM_ERROR_INVAL;
3230     }
3231
3232         if (baseFid == 0) {
3233                 baseDirp = cm_rootSCachep;
3234                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3235         }
3236         else {
3237         baseFidp = smb_FindFID(vcp, baseFid, 0);
3238         if (!baseFidp) {
3239                 osi_Log1(afsd_logp, "NTCreateX Invalid base fid [%d]", baseFid);
3240                 free(realPathp);
3241                 cm_ReleaseUser(userp);
3242                 return CM_ERROR_INVAL;
3243         }
3244                 baseDirp = baseFidp->scp;
3245                 tidPathp = NULL;
3246         }
3247
3248     osi_Log1(afsd_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(afsd_logp,tidPathp));
3249         
3250     /* compute open mode */
3251         fidflags = 0;
3252         if (desiredAccess & DELETE)
3253                 fidflags |= SMB_FID_OPENDELETE;
3254         if (desiredAccess & AFS_ACCESS_READ)
3255                 fidflags |= SMB_FID_OPENREAD;
3256         if (desiredAccess & AFS_ACCESS_WRITE)
3257                 fidflags |= SMB_FID_OPENWRITE;
3258
3259         dscp = NULL;
3260         code = 0;
3261         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3262                         userp, tidPathp, &req, &scp);
3263         if (code == 0) foundscp = TRUE;
3264         if (code != 0
3265             || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3266                 /* look up parent directory */