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