windows-updates-including-dont-lose-tokens-20011110
[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                 if (strcmp(lastComp, "\\desktop.ini") == 0) {
1152                         code = cm_NameI(cm_rootSCachep, spacep->data,
1153                                         CM_FLAG_CASEFOLD
1154                                           | CM_FLAG_DIRSEARCH
1155                                           | CM_FLAG_FOLLOW,
1156                                         userp, tidPathp, &req, &dscp);
1157                         if (code == 0) {
1158                                 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1159                                     && !dscp->mountRootFidp)
1160                                         code = CM_ERROR_NOSUCHFILE;
1161                                 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1162                                         cm_buf_t *bp = buf_Find(dscp, &hzero);
1163                                         if (bp)
1164                                                 buf_Release(bp);
1165                                         else
1166                                                 code = CM_ERROR_NOSUCHFILE;
1167                                 }
1168                                 cm_ReleaseSCache(dscp);
1169                                 if (code) {
1170                                         cm_FreeSpace(spacep);
1171                                         cm_ReleaseUser(userp);
1172                                         smb_SendTran2Error(vcp, p, opx, code);
1173                                         smb_FreeTran2Packet(outp);
1174                                         return 0;
1175                                 }
1176                         }
1177                 }
1178                 cm_FreeSpace(spacep);
1179         }
1180
1181         /* now do namei and stat, and copy out the info */
1182         code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1183                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1184
1185         if (code) {
1186                 cm_ReleaseUser(userp);
1187                 smb_SendTran2Error(vcp, p, opx, code);
1188                 smb_FreeTran2Packet(outp);
1189                 return 0;
1190         }
1191
1192         lock_ObtainMutex(&scp->mx);
1193         code = cm_SyncOp(scp, NULL, userp, &req, 0,
1194                 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1195         if (code) goto done;
1196         
1197         /* now we have the status in the cache entry, and everything is locked.
1198          * Marshall the output data.
1199          */
1200         op = outp->datap;
1201         /* for info level 108, figure out short name */
1202         if (infoLevel == 0x108) {
1203                 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1204                                         tidPathp, scp->fid.vnode, shortName,
1205                                         (size_t *) &len);
1206                 if (code) {
1207                         goto done;
1208                 }
1209
1210                 op = outp->datap;
1211                 *((u_long *)op) = len * 2; op += 4;
1212                 mbstowcs((unsigned short *)op, shortName, len);
1213                 op += (len * 2);
1214
1215                 goto done;
1216         }
1217         if (infoLevel == 1 || infoLevel == 2) {
1218                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1219                 *((u_long *)op) = dosTime; op += 4;     /* creation time */
1220                 *((u_long *)op) = dosTime; op += 4;     /* access time */
1221                 *((u_long *)op) = dosTime; op += 4;     /* write time */
1222                 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1223                 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1224                 attributes = smb_Attributes(scp);
1225                 *((u_short *)op) = attributes; op += 2; /* attributes */
1226         }
1227         else if (infoLevel == 0x101) {
1228                 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1229                 *((FILETIME *)op) = ft; op += 8;        /* creation time */
1230                 *((FILETIME *)op) = ft; op += 8;        /* last access time */
1231                 *((FILETIME *)op) = ft; op += 8;        /* last write time */
1232                 *((FILETIME *)op) = ft; op += 8;        /* last change time */
1233                 extAttributes = smb_ExtAttributes(scp);
1234                 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1235                 *((u_long *)op) = 0; op += 4;   /* don't know what this is */
1236         }
1237         else if (infoLevel == 0x102) {
1238                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
1239                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
1240                 *((u_long *)op) = scp->linkCount; op += 4;
1241                 *op++ = 0;
1242                 *op++ = 0;
1243                 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1244                 *op++ = 0;
1245         }
1246         else if (infoLevel == 0x103) {
1247                 memset(op, 0, 4); op += 4;      /* EA size */
1248         }
1249
1250         /* now, if we are being asked about extended attrs, return a 0 size */
1251         if (infoLevel == 2) {
1252                 *((u_long *)op) = 0; op += 4;
1253         }
1254         
1255
1256         /* send and free the packets */
1257 done:
1258         lock_ReleaseMutex(&scp->mx);
1259         cm_ReleaseSCache(scp);
1260         cm_ReleaseUser(userp);
1261         if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1262         else smb_SendTran2Error(vcp, p, opx, code);
1263         smb_FreeTran2Packet(outp);
1264
1265         return 0;
1266 }
1267
1268 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1269 {
1270         return CM_ERROR_BADOP;
1271 }
1272
1273 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1274 {
1275         smb_tran2Packet_t *outp;
1276         FILETIME ft;
1277         unsigned long attributes;
1278         unsigned short infoLevel;
1279         int nbytesRequired;
1280         unsigned short fid;
1281         cm_user_t *userp;
1282         smb_fid_t *fidp;
1283         cm_scache_t *scp;
1284         char *op;
1285         long code;
1286         cm_req_t req;
1287
1288         cm_InitReq(&req);
1289
1290         fid = p->parmsp[0];
1291         fidp = smb_FindFID(vcp, fid, 0);
1292
1293         if (fidp == NULL) {
1294                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
1295                 return 0;
1296         }
1297
1298         infoLevel = p->parmsp[1];
1299         if (infoLevel == 0x101) nbytesRequired = 40;
1300         else if (infoLevel == 0x102) nbytesRequired = 24;
1301         else if (infoLevel == 0x103) nbytesRequired = 4;
1302         else if (infoLevel == 0x104) nbytesRequired = 6;
1303         else {
1304                 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1305                          p->opcode, infoLevel);
1306                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1307                 return 0;
1308         }
1309         osi_Log2(afsd_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1310
1311         outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1312
1313         if (infoLevel > 0x100)
1314                 outp->totalParms = 2;
1315         else
1316                 outp->totalParms = 0;
1317         outp->totalData = nbytesRequired;
1318
1319         userp = smb_GetTran2User(vcp, p);
1320
1321         scp = fidp->scp;
1322         lock_ObtainMutex(&scp->mx);
1323         code = cm_SyncOp(scp, NULL, userp, &req, 0,
1324                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1325         if (code) goto done;
1326
1327         /* now we have the status in the cache entry, and everything is locked.
1328          * Marshall the output data.
1329          */
1330         op = outp->datap;
1331         if (infoLevel == 0x101) {
1332                 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1333                 *((FILETIME *)op) = ft; op += 8;        /* creation time */
1334                 *((FILETIME *)op) = ft; op += 8;        /* last access time */
1335                 *((FILETIME *)op) = ft; op += 8;        /* last write time */
1336                 *((FILETIME *)op) = ft; op += 8;        /* last change time */
1337                 attributes = smb_ExtAttributes(scp);
1338                 *((u_long *)op) = attributes; op += 4;
1339                 *((u_long *)op) = 0; op += 4;
1340         }
1341         else if (infoLevel == 0x102) {
1342                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
1343                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
1344                 *((u_long *)op) = scp->linkCount; op += 4;
1345                 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1346                 *op++ = 0;
1347                 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1348                 *op++ = 0;
1349         }
1350         else if (infoLevel == 0x103) {
1351                 *((u_long *)op) = 0; op += 4;
1352         }
1353         else if (infoLevel == 0x104) {
1354                 unsigned long len;
1355                 char *name;
1356
1357                 if (fidp->NTopen_wholepathp)
1358                         name = fidp->NTopen_wholepathp;
1359                 else
1360                         name = "\\";    /* probably can't happen */
1361                 len = strlen(name);
1362                 outp->totalData = (len*2) + 4;  /* this is actually what we want to return */
1363                 *((u_long *)op) = len * 2; op += 4;
1364                 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1365         }
1366
1367         /* send and free the packets */
1368 done:
1369         lock_ReleaseMutex(&scp->mx);
1370         cm_ReleaseUser(userp);
1371         smb_ReleaseFID(fidp);
1372         if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1373         else smb_SendTran2Error(vcp, p, opx, code);
1374         smb_FreeTran2Packet(outp);
1375
1376         return 0;
1377 }
1378
1379 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1380 {
1381         long code;
1382         unsigned short fid;
1383         smb_fid_t *fidp;
1384         unsigned short infoLevel;
1385         smb_tran2Packet_t *outp;
1386         cm_user_t *userp;
1387         cm_scache_t *scp;
1388         cm_req_t req;
1389
1390         cm_InitReq(&req);
1391
1392         fid = p->parmsp[0];
1393         fidp = smb_FindFID(vcp, fid, 0);
1394
1395         if (fidp == NULL) {
1396                 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1397                 return 0;
1398         }
1399
1400         infoLevel = p->parmsp[1];
1401         if (infoLevel > 0x104 || infoLevel < 0x101) {
1402                 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1403                          p->opcode, infoLevel);
1404                 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1405                 return 0;
1406         }
1407
1408         if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1409                 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1410                 return 0;
1411         }
1412         if ((infoLevel == 0x103 || infoLevel == 0x104)
1413             && !(fidp->flags & SMB_FID_OPENWRITE)) {
1414                 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1415                 return 0;
1416         }
1417
1418         osi_Log1(afsd_logp, "T2 SFileInfo type 0x%x", infoLevel);
1419
1420         outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1421
1422         outp->totalParms = 2;
1423         outp->totalData = 0;
1424
1425         userp = smb_GetTran2User(vcp, p);
1426
1427         scp = fidp->scp;
1428
1429         if (infoLevel == 0x101) {
1430                 FILETIME lastMod;
1431                 unsigned int attribute;
1432                 cm_attr_t attr;
1433
1434                 /* lock the vnode with a callback; we need the current status
1435                  * to determine what the new status is, in some cases.
1436                  */
1437                 lock_ObtainMutex(&scp->mx);
1438                 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1439                                  CM_SCACHESYNC_GETSTATUS
1440                                  | CM_SCACHESYNC_NEEDCALLBACK);
1441                 if (code) {
1442                         lock_ReleaseMutex(&scp->mx);
1443                         goto done;
1444                 }
1445
1446                 /* prepare for setattr call */
1447                 attr.mask = 0;
1448                 lastMod = *((FILETIME *)(p->datap + 16));
1449                 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod))) {
1450                         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1451                         smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1452                                                         &lastMod);
1453                         fidp->flags |= SMB_FID_MTIMESETDONE;
1454                 }
1455                 attribute = *((u_long *)(p->datap + 32));
1456                 if (attribute != 0) {
1457                         if ((scp->unixModeBits & 0222)
1458                             && (attribute & 1) != 0) {
1459                                 /* make a writable file read-only */
1460                                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1461                                 attr.unixModeBits = scp->unixModeBits & ~0222;
1462                         }
1463                         else if ((scp->unixModeBits & 0222) == 0
1464                                  && (attribute & 1) == 0) {
1465                                 /* make a read-only file writable */
1466                                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1467                                 attr.unixModeBits = scp->unixModeBits | 0222;
1468                         }
1469                 }
1470                 lock_ReleaseMutex(&scp->mx);
1471
1472                 /* call setattr */
1473                 if (attr.mask)
1474                         code = cm_SetAttr(scp, &attr, userp, &req);
1475                 else
1476                         code = 0;
1477         }
1478         else if (infoLevel == 0x103 || infoLevel == 0x104) {
1479                 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1480                 cm_attr_t attr;
1481
1482                 attr.mask = CM_ATTRMASK_LENGTH;
1483                 attr.length.LowPart = size.LowPart;
1484                 attr.length.HighPart = size.HighPart;
1485                 code = cm_SetAttr(scp, &attr, userp, &req);
1486         }
1487         else if (infoLevel == 0x102) {
1488                 if (*((char *)(p->datap))) {
1489                         code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1490                                                 &req);
1491                         if (code == 0)
1492                                 fidp->flags |= SMB_FID_DELONCLOSE;
1493                 }
1494                 else {
1495                         code = 0;
1496                         fidp->flags &= ~SMB_FID_DELONCLOSE;
1497                 }
1498         }
1499 done:
1500         cm_ReleaseUser(userp);
1501         smb_ReleaseFID(fidp);
1502         if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1503         else smb_SendTran2Error(vcp, p, op, code);
1504         smb_FreeTran2Packet(outp);
1505
1506         return 0;
1507 }
1508
1509 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1510 {
1511         return CM_ERROR_BADOP;
1512 }
1513
1514 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1515 {
1516         return CM_ERROR_BADOP;
1517 }
1518
1519 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1520 {
1521         return CM_ERROR_BADOP;
1522 }
1523
1524 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1525 {
1526         return CM_ERROR_BADOP;
1527 }
1528
1529 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1530 {
1531         return CM_ERROR_BADOP;
1532 }
1533
1534 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1535         smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1536         cm_req_t *reqp)
1537 {
1538         long code;
1539         cm_scache_t *scp;
1540         cm_scache_t *targetScp;                 /* target if scp is a symlink */
1541         char *dptr;
1542         long dosTime;
1543         FILETIME ft;
1544         int shortTemp;
1545         unsigned short attr;
1546         unsigned long lattr;
1547         smb_dirListPatch_t *patchp;
1548         smb_dirListPatch_t *npatchp;
1549         
1550         for(patchp = *dirPatchespp; patchp; patchp =
1551                 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1552                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1553                 if (code) continue;
1554                 lock_ObtainMutex(&scp->mx);
1555                 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1556                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1557                 if (code) {
1558                         lock_ReleaseMutex(&scp->mx);
1559                         cm_ReleaseSCache(scp);
1560                         continue;
1561                 }
1562                 
1563                 /* now watch for a symlink */
1564                 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1565                         lock_ReleaseMutex(&scp->mx);
1566                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp,
1567                                                   reqp);
1568                         if (code == 0) {
1569                                 /* we have a more accurate file to use (the
1570                                  * target of the symbolic link).  Otherwise,
1571                                  * we'll just use the symlink anyway.
1572                                  */
1573                                 osi_Log2(afsd_logp, "symlink vp %x to vp %x",
1574                                          scp, targetScp);
1575                                 cm_ReleaseSCache(scp);
1576                                 scp = targetScp;
1577                         }
1578                         lock_ObtainMutex(&scp->mx);
1579                 }
1580
1581                 dptr = patchp->dptr;
1582
1583                 if (infoLevel >= 0x101) {
1584                         /* get filetime */
1585                         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1586
1587                         /* copy to Creation Time */
1588                         *((FILETIME *)dptr) = ft;
1589                         dptr += 8;
1590
1591                         /* copy to Last Access Time */
1592                         *((FILETIME *)dptr) = ft;
1593                         dptr += 8;
1594
1595                         /* copy to Last Write Time */
1596                         *((FILETIME *)dptr) = ft;
1597                         dptr += 8;
1598
1599                         /* copy to Change Time */
1600                         *((FILETIME *)dptr) = ft;
1601                         dptr += 8;
1602
1603                         /* Use length for both file length and alloc length */
1604                         *((LARGE_INTEGER *)dptr) = scp->length;
1605                         dptr += 8;
1606                         *((LARGE_INTEGER *)dptr) = scp->length;
1607                         dptr += 8;
1608
1609                         /* Copy attributes */
1610                         lattr = smb_ExtAttributes(scp);
1611                         *((u_long *)dptr) = lattr;
1612                         dptr += 4;
1613                 }
1614                 else {
1615                         /* get dos time */
1616                         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1617
1618                         /* and copy out date */
1619                         shortTemp = (dosTime>>16) & 0xffff;
1620                         *((u_short *)dptr) = shortTemp;
1621                         dptr += 2;
1622
1623                         /* copy out creation time */
1624                         shortTemp = dosTime & 0xffff;
1625                         *((u_short *)dptr) = shortTemp;
1626                         dptr += 2;
1627
1628                         /* and copy out date */
1629                         shortTemp = (dosTime>>16) & 0xffff;
1630                         *((u_short *)dptr) = shortTemp;
1631                         dptr += 2;
1632                         
1633                         /* copy out access time */
1634                         shortTemp = dosTime & 0xffff;
1635                         *((u_short *)dptr) = shortTemp;
1636                         dptr += 2;
1637
1638                         /* and copy out date */
1639                         shortTemp = (dosTime>>16) & 0xffff;
1640                         *((u_short *)dptr) = shortTemp;
1641                         dptr += 2;
1642                         
1643                         /* copy out mod time */
1644                         shortTemp = dosTime & 0xffff;
1645                         *((u_short *)dptr) = shortTemp;
1646                         dptr += 2;
1647
1648                         /* copy out file length and alloc length,
1649                          * using the same for both
1650                          */
1651                         *((u_long *)dptr) = scp->length.LowPart;
1652                         dptr += 4;
1653                         *((u_long *)dptr) = scp->length.LowPart;
1654                         dptr += 4;
1655
1656                         /* finally copy out attributes as short */
1657                         attr = smb_Attributes(scp);
1658                         *dptr++ = attr & 0xff;
1659                         *dptr++ = (attr >> 8) & 0xff;
1660                 }
1661
1662                 lock_ReleaseMutex(&scp->mx);
1663                 cm_ReleaseSCache(scp);
1664         }
1665         
1666         /* now free the patches */
1667         for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1668                 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1669                 free(patchp);
1670         }
1671         
1672         /* and mark the list as empty */
1673         *dirPatchespp = NULL;
1674
1675         return code;
1676 }
1677
1678 /* do a case-folding search of the star name mask with the name in namep.
1679  * Return 1 if we match, otherwise 0.
1680  */
1681 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1682 {
1683         unsigned char tcp1, tcp2;       /* Pattern characters */
1684         unsigned char tcn1;             /* Name characters */
1685         int sawDot = 0, sawStar = 0;
1686         char *starNamep, *starMaskp;
1687         static char nullCharp[] = {0};
1688
1689         /* make sure we only match 8.3 names, if requested */
1690         if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) return 0;
1691
1692         /* loop */
1693         while (1) {
1694                 /* Next pattern character */
1695                 tcp1 = *maskp++;
1696
1697                 /* Next name character */
1698                 tcn1 = *namep;
1699
1700                 if (tcp1 == 0) {
1701                         /* 0 - end of pattern */
1702                         if (tcn1 == 0)
1703                                 return 1;
1704                         else
1705                                 return 0;
1706                 }
1707                 else if (tcp1 == '.' || tcp1 == '"') {
1708                         if (sawDot) {
1709                                 if (tcn1 == '.') {
1710                                         namep++;
1711                                         continue;
1712                                 } else
1713                                         return 0;
1714                         }
1715                         else {
1716                                 /*
1717                                  * first dot in pattern;
1718                                  * must match dot or end of name
1719                                  */
1720                                 sawDot = 1;
1721                                 if (tcn1 == 0)
1722                                         continue;
1723                                 else if (tcn1 == '.') {
1724                                         sawStar = 0;
1725                                         namep++;
1726                                         continue;
1727                                 }
1728                                 else
1729                                         return 0;
1730                         }
1731                 }
1732                 else if (tcp1 == '?') {
1733                         if (tcn1 == 0 || tcn1 == '.')
1734                                 return 0;
1735                         namep++;
1736                         continue;
1737                 }
1738                 else if (tcp1 == '>') {
1739                         if (tcn1 != 0 && tcn1 != '.')
1740                                 namep++;
1741                         continue;
1742                 }
1743                 else if (tcp1 == '*' || tcp1 == '<') {
1744                         tcp2 = *maskp++;
1745                         if (tcp2 == 0)
1746                                 return 1;
1747                         else if (tcp2 == '.' || tcp2 == '"') {
1748                                 while (tcn1 != '.' && tcn1 != 0)
1749                                         tcn1 = *++namep;
1750                                 if (tcn1 == 0) {
1751                                         if (sawDot)
1752                                                 return 0;
1753                                         else
1754                                                 continue;
1755                                 }
1756                                 else {
1757                                         namep++;
1758                                         continue;
1759                                 }
1760                         }
1761                         else {
1762                                 /*
1763                                  * pattern character after '*' is not null or
1764                                  * period.  If it is '?' or '>', we are not
1765                                  * going to understand it.  If it is '*' or
1766                                  * '<', we are going to skip over it.  None of
1767                                  * these are likely, I hope.
1768                                  */
1769                                 /* skip over '*' and '<' */
1770                                 while (tcp2 == '*' || tcp2 == '<')
1771                                         tcp2 = *maskp++;
1772
1773                                 /* skip over characters that don't match tcp2 */
1774                                 while (tcn1 != '.' && tcn1 != 0
1775                                         && cm_foldUpper[tcn1] != cm_foldUpper[tcp2])
1776                                         tcn1 = *++namep;
1777
1778                                 /* No match */
1779                                 if (tcn1 == '.' || tcn1 == 0)
1780                                         return 0;
1781
1782                                 /* Remember where we are */
1783                                 sawStar = 1;
1784                                 starMaskp = maskp;
1785                                 starNamep = namep;
1786
1787                                 namep++;
1788                                 continue;
1789                         }
1790                 }
1791                 else {
1792                         /* tcp1 is not a wildcard */
1793                         if (cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) {
1794                                 /* they match */
1795                                 namep++;
1796                                 continue;
1797                         }
1798                         /* if trying to match a star pattern, go back */
1799                         if (sawStar) {
1800                                 maskp = starMaskp - 2;
1801                                 namep = starNamep + 1;
1802                                 sawStar = 0;
1803                                 continue;
1804                         }
1805                         /* that's all */
1806                         return 0;
1807                 }
1808         }
1809 }
1810
1811 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1812 {
1813         int attribute;
1814         long nextCookie;
1815         char *tp;
1816         long code;
1817         char *pathp;
1818         cm_dirEntry_t *dep;
1819         int maxCount;
1820         smb_dirListPatch_t *dirListPatchesp;
1821         smb_dirListPatch_t *curPatchp;
1822         cm_buf_t *bufferp;
1823         long temp;
1824         long orbytes;                   /* # of bytes in this output record */
1825         long ohbytes;                   /* # of bytes, except file name */
1826         long onbytes;                   /* # of bytes in name, incl. term. null */
1827         osi_hyper_t dirLength;
1828         osi_hyper_t bufferOffset;
1829         osi_hyper_t curOffset;
1830         osi_hyper_t thyper;
1831         smb_dirSearch_t *dsp;
1832         cm_scache_t *scp;
1833         long entryInDir;
1834         long entryInBuffer;
1835         cm_pageHeader_t *pageHeaderp;
1836         cm_user_t *userp = NULL;
1837         int slotInPage;
1838         int returnedNames;
1839         long nextEntryCookie;
1840         int numDirChunks;               /* # of 32 byte dir chunks in this entry */
1841         char *op;                       /* output data ptr */
1842         char *origOp;                   /* original value of op */
1843         cm_space_t *spacep;             /* for pathname buffer */
1844         long maxReturnData;             /* max # of return data */
1845         long maxReturnParms;            /* max # of return parms */
1846         long bytesInBuffer;             /* # data bytes in the output buffer */
1847         int starPattern;
1848         char *maskp;                    /* mask part of path */
1849         int infoLevel;
1850         int searchFlags;
1851         int eos;
1852         smb_tran2Packet_t *outp;        /* response packet */
1853         char *tidPathp;
1854         int align;
1855         char shortName[13];             /* 8.3 name if needed */
1856         int NeedShortName;
1857         char *shortNameEnd;
1858         int fileType;
1859         cm_fid_t fid;
1860         
1861         cm_req_t req;
1862
1863         cm_InitReq(&req);
1864
1865         eos = 0;
1866         if (p->opcode == 1) {
1867                 /* find first; obtain basic parameters from request */
1868                 attribute = p->parmsp[0];
1869                 maxCount = p->parmsp[1];
1870                 infoLevel = p->parmsp[3];
1871                 searchFlags = p->parmsp[2];
1872                 dsp = smb_NewDirSearch(1);
1873                 dsp->attribute = attribute;
1874                 pathp = ((char *) p->parmsp) + 12;      /* points to path */
1875                 nextCookie = 0;
1876                 maskp = strrchr(pathp, '\\');
1877                 if (maskp == NULL) maskp = pathp;
1878                 else maskp++;   /* skip over backslash */
1879                 strcpy(dsp->mask, maskp);       /* and save mask */
1880                 /* track if this is likely to match a lot of entries */
1881                 starPattern = smb_V3IsStarMask(maskp);
1882         }
1883         else {
1884                 osi_assert(p->opcode == 2);
1885                 /* find next; obtain basic parameters from request or open dir file */
1886                 dsp = smb_FindDirSearch(p->parmsp[0]);
1887                 if (!dsp) return CM_ERROR_BADFD;
1888                 attribute = dsp->attribute;
1889                 maxCount = p->parmsp[1];
1890                 infoLevel = p->parmsp[2];
1891                 searchFlags = p->parmsp[5];
1892                 pathp = NULL;
1893                 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
1894                 maskp = dsp->mask;
1895                 starPattern = 1;        /* assume, since required a Find Next */
1896         }
1897
1898         osi_Log4(afsd_logp,
1899                  "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
1900                  attribute, infoLevel, maxCount, searchFlags);
1901
1902         osi_Log2(afsd_logp, "...T2 search op %d, nextCookie 0x%x",
1903                  p->opcode, nextCookie);
1904
1905         if (infoLevel >= 0x101)
1906                 searchFlags &= ~4;      /* no resume keys */
1907
1908         dirListPatchesp = NULL;
1909
1910         maxReturnData = p->maxReturnData;
1911         if (p->opcode == 1)     /* find first */
1912                 maxReturnParms = 10;    /* bytes */
1913         else
1914                 maxReturnParms = 8;     /* bytes */
1915
1916 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
1917         if (maxReturnData > 6000) maxReturnData = 6000;
1918 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
1919
1920         outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
1921                                           maxReturnData);
1922
1923         osi_Log1(afsd_logp, "T2 receive search dir %s",
1924                         osi_LogSaveString(afsd_logp, pathp));
1925         
1926         /* bail out if request looks bad */
1927         if (p->opcode == 1 && !pathp) {
1928                 return CM_ERROR_BADSMB;
1929         }
1930         
1931         osi_Log2(afsd_logp, "T2 dir search cookie 0x%x, connection %d",
1932                 nextCookie, dsp->cookie);
1933
1934         userp = smb_GetTran2User(vcp, p);
1935
1936         /* try to get the vnode for the path name next */
1937         lock_ObtainMutex(&dsp->mx);
1938         if (dsp->scp) {
1939                 scp = dsp->scp;
1940                 cm_HoldSCache(scp);
1941                 code = 0;
1942         }
1943         else {
1944                 spacep = cm_GetSpace();
1945                 smb_StripLastComponent(spacep->data, NULL, pathp);
1946                 lock_ReleaseMutex(&dsp->mx);
1947
1948                 tidPathp = smb_GetTIDPath(vcp, p->tid);
1949                 code = cm_NameI(cm_rootSCachep, spacep->data,
1950                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
1951                                 userp, tidPathp, &req, &scp);
1952                 cm_FreeSpace(spacep);
1953
1954                 lock_ObtainMutex(&dsp->mx);
1955                 if (code == 0) {
1956                         if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
1957                         dsp->scp = scp;
1958                         /* we need one hold for the entry we just stored into,
1959                          * and one for our own processing.  When we're done
1960                          * with this function, we'll drop the one for our own
1961                          * processing.  We held it once from the namei call,
1962                          * and so we do another hold now.
1963                          */
1964                         cm_HoldSCache(scp);
1965                         lock_ObtainMutex(&scp->mx);
1966                         if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
1967                             && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
1968                                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
1969                                 dsp->flags |= SMB_DIRSEARCH_BULKST;
1970                         }
1971                         lock_ReleaseMutex(&scp->mx);
1972                 }
1973         }
1974         lock_ReleaseMutex(&dsp->mx);
1975         if (code) {
1976                 cm_ReleaseUser(userp);
1977                 smb_FreeTran2Packet(outp);
1978                 smb_DeleteDirSearch(dsp);
1979                 smb_ReleaseDirSearch(dsp);
1980                 return code;
1981         }
1982
1983         /* get the directory size */
1984         lock_ObtainMutex(&scp->mx);
1985         code = cm_SyncOp(scp, NULL, userp, &req, 0,
1986                 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1987         if (code) {
1988                 lock_ReleaseMutex(&scp->mx);
1989                 cm_ReleaseSCache(scp);
1990                 cm_ReleaseUser(userp);
1991                 smb_FreeTran2Packet(outp);
1992                 smb_DeleteDirSearch(dsp);
1993                 smb_ReleaseDirSearch(dsp);
1994                 return code;
1995         }
1996         
1997         dirLength = scp->length;
1998         bufferp = NULL;
1999         bufferOffset.LowPart = bufferOffset.HighPart = 0;
2000         curOffset.HighPart = 0;
2001         curOffset.LowPart = nextCookie;
2002         origOp = outp->datap;
2003
2004         code = 0;
2005         returnedNames = 0;
2006         bytesInBuffer = 0;
2007         while (1) {
2008                 op = origOp;
2009                 if (searchFlags & 4)
2010                         /* skip over resume key */
2011                         op += 4;
2012
2013                 /* make sure that curOffset.LowPart doesn't point to the first
2014                  * 32 bytes in the 2nd through last dir page, and that it doesn't
2015                  * point at the first 13 32-byte chunks in the first dir page,
2016                  * since those are dir and page headers, and don't contain useful
2017                  * information.
2018                  */
2019                 temp = curOffset.LowPart & (2048-1);
2020                 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2021                         /* we're in the first page */
2022                         if (temp < 13*32) temp = 13*32;
2023                 }
2024                 else {
2025                         /* we're in a later dir page */
2026                         if (temp < 32) temp = 32;
2027                 }
2028                 
2029                 /* make sure the low order 5 bits are zero */
2030                 temp &= ~(32-1);
2031                 
2032                 /* now put temp bits back ito curOffset.LowPart */
2033                 curOffset.LowPart &= ~(2048-1);
2034                 curOffset.LowPart |= temp;
2035
2036                 /* check if we've returned all the names that will fit in the
2037                  * response packet; we check return count as well as the number
2038                  * of bytes requested.  We check the # of bytes after we find
2039                  * the dir entry, since we'll need to check its size.
2040                  */
2041                 if (returnedNames >= maxCount) break;
2042                 
2043                 /* check if we've passed the dir's EOF */
2044                 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2045                         eos = 1;
2046                         break;
2047                 }
2048                 
2049                 /* see if we can use the bufferp we have now; compute in which
2050                  * page the current offset would be, and check whether that's
2051                  * the offset of the buffer we have.  If not, get the buffer.
2052                  */
2053                 thyper.HighPart = curOffset.HighPart;
2054                 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2055                 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2056                         /* wrong buffer */
2057                         if (bufferp) {
2058                                 buf_Release(bufferp);
2059                                 bufferp = NULL;
2060                         }
2061                         lock_ReleaseMutex(&scp->mx);
2062                         lock_ObtainRead(&scp->bufCreateLock);
2063                         code = buf_Get(scp, &thyper, &bufferp);
2064                         lock_ReleaseRead(&scp->bufCreateLock);
2065
2066                         /* now, if we're doing a star match, do bulk fetching
2067                          * of all of the status info for files in the dir.
2068                          */
2069                         if (starPattern) {
2070                                 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2071                                                           infoLevel, userp,
2072                                                           &req);
2073                                 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2074                                     && LargeIntegerGreaterThanOrEqualTo(
2075                                                 thyper, scp->bulkStatProgress)) {
2076                                         /* Don't bulk stat if risking timeout */
2077                                         int now = GetCurrentTime();
2078                                         if (now - req.startTime > 5000) {
2079                                                 scp->bulkStatProgress = thyper;
2080                                                 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2081                                                 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2082                                         } else
2083                                                 cm_TryBulkStat(scp, &thyper,
2084                                                                userp, &req);
2085                                 }
2086                         }
2087
2088                         lock_ObtainMutex(&scp->mx);
2089                         if (code) break;
2090                         bufferOffset = thyper;
2091
2092                         /* now get the data in the cache */
2093                         while (1) {
2094                                 code = cm_SyncOp(scp, bufferp, userp, &req,
2095                                         PRSFS_LOOKUP,
2096                                         CM_SCACHESYNC_NEEDCALLBACK
2097                                         | CM_SCACHESYNC_READ);
2098                                 if (code) break;
2099                                 
2100                                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2101                                 
2102                                 /* otherwise, load the buffer and try again */
2103                                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2104                                                     &req);
2105                                 if (code) break;
2106                         }
2107                         if (code) {
2108                                 buf_Release(bufferp);
2109                                 bufferp = NULL;
2110                                 break;
2111                         }
2112                 }       /* if (wrong buffer) ... */
2113                 
2114                 /* now we have the buffer containing the entry we're interested
2115                  * in; copy it out if it represents a non-deleted entry.
2116                  */
2117                 entryInDir = curOffset.LowPart & (2048-1);
2118                 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2119
2120                 /* page header will help tell us which entries are free.  Page
2121                  * header can change more often than once per buffer, since
2122                  * AFS 3 dir page size may be less than (but not more than)
2123                  * a buffer package buffer.
2124                  */
2125                 /* only look intra-buffer */
2126                 temp = curOffset.LowPart & (buf_bufferSize - 1);
2127                 temp &= ~(2048 - 1);    /* turn off intra-page bits */
2128                 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2129
2130                 /* now determine which entry we're looking at in the page.
2131                  * If it is free (there's a free bitmap at the start of the
2132                  * dir), we should skip these 32 bytes.
2133                  */
2134                 slotInPage = (entryInDir & 0x7e0) >> 5;
2135                 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2136                         & (1 << (slotInPage & 0x7)))) {
2137                         /* this entry is free */
2138                         numDirChunks = 1;       /* only skip this guy */
2139                         goto nextEntry;
2140                 }
2141
2142                 tp = bufferp->datap + entryInBuffer;
2143                 dep = (cm_dirEntry_t *) tp;     /* now points to AFS3 dir entry */
2144
2145                 /* while we're here, compute the next entry's location, too,
2146                  * since we'll need it when writing out the cookie into the dir
2147                  * listing stream.
2148                  *
2149                  * XXXX Probably should do more sanity checking.
2150                  */
2151                 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2152                 
2153                 /* compute offset of cookie representing next entry */
2154                 nextEntryCookie = curOffset.LowPart
2155                                     + (CM_DIR_CHUNKSIZE * numDirChunks);
2156
2157                 /* Need 8.3 name? */
2158                 NeedShortName = 0;
2159                 if (infoLevel == 0x104
2160                     && dep->fid.vnode != 0
2161                     && !cm_Is8Dot3(dep->name)) {
2162                         cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2163                         NeedShortName = 1;
2164                 }
2165
2166                 if (dep->fid.vnode != 0
2167                     && (smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)
2168                         || (NeedShortName
2169                             && smb_V3MatchMask(shortName, maskp,
2170                                                 CM_FLAG_CASEFOLD)))) {
2171
2172                         /* Eliminate entries that don't match requested
2173                            attributes */
2174                         if (!(dsp->attribute & 0x10))  /* no directories */
2175                         {
2176                             /* We have already done the cm_TryBulkStat above */
2177                             fid.cell = scp->fid.cell;
2178                             fid.volume = scp->fid.volume;
2179                             fid.vnode = ntohl(dep->fid.vnode);
2180                             fid.unique = ntohl(dep->fid.unique);
2181                             fileType = cm_FindFileType(&fid);
2182                             /*osi_Log2(afsd_logp, "smb_ReceiveTran2SearchDir: file %s "
2183                               "has filetype %d", dep->name,
2184                               fileType);*/
2185                             if (fileType == CM_SCACHETYPE_DIRECTORY)
2186                               goto nextEntry;
2187                         }
2188
2189                         /* finally check if this name will fit */
2190
2191                         /* standard dir entry stuff */
2192                         if (infoLevel < 0x101)
2193                                 ohbytes = 23;   /* pre-NT */
2194                         else if (infoLevel == 0x103)
2195                                 ohbytes = 12;   /* NT names only */
2196                         else
2197                                 ohbytes = 64;   /* NT */
2198
2199                         if (infoLevel == 0x104)
2200                                 ohbytes += 26;  /* Short name & length */
2201
2202                         if (searchFlags & 4) {
2203                                 ohbytes += 4;   /* if resume key required */
2204                         }
2205
2206                         if (infoLevel != 1
2207                             && infoLevel != 0x101
2208                             && infoLevel != 0x103)
2209                                 ohbytes += 4;   /* EASIZE */
2210
2211                         /* add header to name & term. null */
2212                         orbytes = onbytes + ohbytes + 1;
2213
2214                         /* now, we round up the record to a 4 byte alignment,
2215                          * and we make sure that we have enough room here for
2216                          * even the aligned version (so we don't have to worry
2217                          * about an * overflow when we pad things out below).
2218                          * That's the reason for the alignment arithmetic below.
2219                          */
2220                         if (infoLevel >= 0x101)
2221                                 align = (4 - (orbytes & 3)) & 3;
2222                         else
2223                                 align = 0;
2224                         if (orbytes + bytesInBuffer + align > maxReturnData)
2225                                 break;
2226
2227                         /* this is one of the entries to use: it is not deleted
2228                          * and it matches the star pattern we're looking for.
2229                          * Put out the name, preceded by its length.
2230                          */
2231                         /* First zero everything else */
2232                         memset(origOp, 0, ohbytes);
2233
2234                         if (infoLevel <= 0x101)
2235                                 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2236                         else if (infoLevel == 0x103)
2237                                 *((u_long *)(op + 8)) = onbytes;
2238                         else
2239                                 *((u_long *)(op + 60)) = onbytes;
2240                         strcpy(origOp+ohbytes, dep->name);
2241
2242                         /* Short name if requested and needed */
2243                         if (infoLevel == 0x104) {
2244                                 if (NeedShortName) {
2245                                         strcpy(op + 70, shortName);
2246                                         *(op + 68) = shortNameEnd - shortName;
2247                                 }
2248                         }
2249
2250                         /* now, adjust the # of entries copied */
2251                         returnedNames++;
2252
2253                         /* NextEntryOffset and FileIndex */
2254                         if (infoLevel >= 101) {
2255                                 int entryOffset = orbytes + align;
2256                                 *((u_long *)op) = entryOffset;
2257                                 *((u_long *)(op+4)) = nextEntryCookie;
2258                         }
2259
2260                         /* now we emit the attribute.  This is tricky, since
2261                          * we need to really stat the file to find out what
2262                          * type of entry we've got.  Right now, we're copying
2263                          * out data from * a buffer, while holding the scp
2264                          * locked, so it isn't really convenient to stat
2265                          * something now.  We'll put in a place holder
2266                          * now, and make a second pass before returning this
2267                          * to get the real attributes.  So, we just skip the
2268                          * data for now, and adjust it later.  We allocate a
2269                          * patch record to make it easy to find this point
2270                          * later.  The replay will happen at a time when it is
2271                          * safe to unlock the directory.
2272                          */
2273                         if (infoLevel != 0x103) {
2274                                 curPatchp = malloc(sizeof(*curPatchp));
2275                                 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2276                                          &curPatchp->q);
2277                                 curPatchp->dptr = op;
2278                                 if (infoLevel >= 0x101)
2279                                         curPatchp->dptr += 8;
2280                                 curPatchp->fid.cell = scp->fid.cell;
2281                                 curPatchp->fid.volume = scp->fid.volume;
2282                                 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2283                                 curPatchp->fid.unique = ntohl(dep->fid.unique);
2284
2285                                 /* temp */
2286                                 curPatchp->dep = dep;
2287                         }
2288
2289                         if (searchFlags & 4)
2290                                 /* put out resume key */
2291                                 *((u_long *)origOp) = nextEntryCookie;
2292
2293                         /* Adjust byte ptr and count */
2294                         origOp += orbytes;      /* skip entire record */
2295                         bytesInBuffer += orbytes;
2296
2297                         /* and pad the record out */
2298                         while (--align >= 0) {
2299                                 *origOp++ = 0;
2300                                 bytesInBuffer++;
2301                         }
2302                         
2303                 }       /* if we're including this name */
2304                 
2305 nextEntry:
2306                 /* and adjust curOffset to be where the new cookie is */
2307                 thyper.HighPart = 0;
2308                 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2309                 curOffset = LargeIntegerAdd(thyper, curOffset);
2310         }               /* while copying data for dir listing */
2311
2312         /* release the mutex */
2313         lock_ReleaseMutex(&scp->mx);
2314         if (bufferp) buf_Release(bufferp);
2315
2316         /* apply and free last set of patches; if not doing a star match, this
2317          * will be empty, but better safe (and freeing everything) than sorry.
2318          */
2319         smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2320                                   &req);
2321         
2322         /* now put out the final parameters */
2323         if (returnedNames == 0) eos = 1;
2324         if (p->opcode == 1) {
2325                 /* find first */
2326                 outp->parmsp[0] = (unsigned short) dsp->cookie;
2327                 outp->parmsp[1] = returnedNames;
2328                 outp->parmsp[2] = eos;
2329                 outp->parmsp[3] = 0;            /* nothing wrong with EAS */
2330                 outp->parmsp[4] = 0;    /* don't need last name to continue
2331                                          * search, cookie is enough.  Normally,
2332                                          * this is the offset of the file name
2333                                          * of the last entry returned.
2334                                          */
2335                 outp->totalParms = 10;  /* in bytes */
2336         }
2337         else {
2338                 /* find next */
2339                 outp->parmsp[0] = returnedNames;
2340                 outp->parmsp[1] = eos;
2341                 outp->parmsp[2] = 0;    /* EAS error */
2342                 outp->parmsp[3] = 0;    /* last name, as above */
2343                 outp->totalParms = 8;   /* in bytes */
2344         }
2345
2346         /* return # of bytes in the buffer */
2347         outp->totalData = bytesInBuffer;
2348
2349         osi_Log2(afsd_logp, "T2 search dir done, %d names, code %d",
2350                 returnedNames, code);
2351
2352         /* Return error code if unsuccessful on first request */
2353         if (code == 0 && p->opcode == 1 && returnedNames == 0)
2354                 code = CM_ERROR_NOSUCHFILE;
2355
2356         /* if we're supposed to close the search after this request, or if
2357          * we're supposed to close the search if we're done, and we're done,
2358          * or if something went wrong, close the search.
2359          */
2360         /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2361         if ((searchFlags & 1) || (returnedNames == 0)
2362                 || code != 0) smb_DeleteDirSearch(dsp);
2363         if (code)
2364                 smb_SendTran2Error(vcp, p, opx, code);
2365         else {
2366                 smb_SendTran2Packet(vcp, outp, opx);
2367         }
2368         smb_FreeTran2Packet(outp);
2369         smb_ReleaseDirSearch(dsp);
2370         cm_ReleaseSCache(scp);
2371         cm_ReleaseUser(userp);
2372         return 0;
2373 }
2374
2375 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2376 {
2377         int dirHandle;
2378         smb_dirSearch_t *dsp;
2379
2380         dirHandle = smb_GetSMBParm(inp, 0);
2381         
2382         osi_Log1(afsd_logp, "SMB3 find close handle %d", dirHandle);
2383
2384         dsp = smb_FindDirSearch(dirHandle);
2385         
2386         if (!dsp)
2387                 return CM_ERROR_BADFD;
2388         
2389         /* otherwise, we have an FD to destroy */
2390         smb_DeleteDirSearch(dsp);
2391         smb_ReleaseDirSearch(dsp);
2392         
2393         /* and return results */
2394         smb_SetSMBDataLength(outp, 0);
2395
2396         return 0;
2397 }
2398
2399 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2400 {
2401         smb_SetSMBDataLength(outp, 0);
2402         return 0;
2403 }
2404
2405 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2406 {
2407         char *pathp;
2408         long code;
2409         cm_space_t *spacep;
2410         int excl;
2411         cm_user_t *userp;
2412         cm_scache_t *dscp;              /* dir we're dealing with */
2413         cm_scache_t *scp;               /* file we're creating */
2414         cm_attr_t setAttr;
2415         int initialModeBits;
2416         smb_fid_t *fidp;
2417         int attributes;
2418         char *lastNamep;
2419         long dosTime;
2420         int openFun;
2421         int trunc;
2422         int openMode;
2423         int extraInfo;
2424         int openAction;
2425         int parmSlot;                   /* which parm we're dealing with */
2426         char *tidPathp;
2427         cm_req_t req;
2428
2429         cm_InitReq(&req);
2430
2431         scp = NULL;
2432         
2433         extraInfo = (smb_GetSMBParm(inp, 2) & 1);       /* return extra info */
2434         openFun = smb_GetSMBParm(inp, 8);       /* open function */
2435         excl = ((openFun & 3) == 0);
2436         trunc = ((openFun & 3) == 2);           /* truncate it */
2437         openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2438         openAction = 0;                 /* tracks what we did */
2439
2440         attributes = smb_GetSMBParm(inp, 5);
2441         dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2442         
2443         /* compute initial mode bits based on read-only flag in attributes */
2444         initialModeBits = 0666;
2445         if (attributes & 1) initialModeBits &= ~0222;
2446         
2447         pathp = smb_GetSMBData(inp, NULL);
2448
2449         spacep = inp->spacep;
2450         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2451
2452         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2453                 /* special case magic file name for receiving IOCTL requests
2454                  * (since IOCTL calls themselves aren't getting through).
2455                  */
2456                 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2457                 smb_SetupIoctlFid(fidp, spacep);
2458
2459                 /* set inp->fid so that later read calls in same msg can find fid */
2460                 inp->fid = fidp->fid;
2461         
2462                 /* copy out remainder of the parms */
2463                 parmSlot = 2;
2464                 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2465                 if (extraInfo) {
2466                         smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2467                         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* mod time */
2468                         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2469                         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* len */
2470                         smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2471                         smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2472                         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2473                         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2474                 }
2475                 /* and the final "always present" stuff */
2476                 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2477                 /* next write out the "unique" ID */
2478                 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2479                 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2480                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2481                 smb_SetSMBDataLength(outp, 0);
2482
2483                 /* and clean up fid reference */
2484                 smb_ReleaseFID(fidp);
2485                 return 0;
2486         }
2487
2488         userp = smb_GetUser(vcp, inp);
2489
2490         dscp = NULL;
2491         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2492         code = cm_NameI(cm_rootSCachep, pathp,
2493                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2494                 userp, tidPathp, &req, &scp);
2495         if (code != 0) {
2496                 code = cm_NameI(cm_rootSCachep, spacep->data,
2497                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2498                                 userp, tidPathp, &req, &dscp);
2499
2500                 if (code) {
2501                         cm_ReleaseUser(userp);
2502                         return code;
2503                 }
2504         
2505                 /* otherwise, scp points to the parent directory.  Do a lookup,
2506                  * and truncate the file if we find it, otherwise we create the
2507                  * file.
2508                  */
2509                 if (!lastNamep) lastNamep = pathp;
2510                 else lastNamep++;
2511                 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2512                                  &req, &scp);
2513                 if (code && code != CM_ERROR_NOSUCHFILE) {
2514                         cm_ReleaseSCache(dscp);
2515                         cm_ReleaseUser(userp);
2516                         return code;
2517                 }
2518         }
2519         
2520         /* if we get here, if code is 0, the file exists and is represented by
2521          * scp.  Otherwise, we have to create it.  The dir may be represented
2522          * by dscp, or we may have found the file directly.  If code is non-zero,
2523          * scp is NULL.
2524          */
2525         if (code == 0) {
2526                 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2527                 if (code) {
2528                         if (dscp) cm_ReleaseSCache(dscp);
2529                         cm_ReleaseSCache(scp);
2530                         cm_ReleaseUser(userp);
2531                         return code;
2532                 }
2533
2534                 if (excl) {
2535                         /* oops, file shouldn't be there */
2536                         if (dscp) cm_ReleaseSCache(dscp);
2537                         cm_ReleaseSCache(scp);
2538                         cm_ReleaseUser(userp);
2539                         return CM_ERROR_EXISTS;
2540                 }
2541
2542                 if (trunc) {
2543                         setAttr.mask = CM_ATTRMASK_LENGTH;
2544                         setAttr.length.LowPart = 0;
2545                         setAttr.length.HighPart = 0;
2546                         code = cm_SetAttr(scp, &setAttr, userp, &req);
2547                         openAction = 3; /* truncated existing file */
2548                 }
2549                 else openAction = 1;    /* found existing file */
2550         }
2551         else if (!(openFun & 0x10)) {
2552                 /* don't create if not found */
2553                 if (dscp) cm_ReleaseSCache(dscp);
2554                 cm_ReleaseUser(userp);
2555                 return CM_ERROR_NOSUCHFILE;
2556         }
2557         else {
2558                 osi_assert(dscp != NULL);
2559                 osi_Log1(afsd_logp, "smb_ReceiveV3OpenX creating file %s",
2560                                 osi_LogSaveString(afsd_logp, lastNamep));
2561                 openAction = 2; /* created file */
2562                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2563                 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2564                 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2565                                  &req);
2566                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2567                         smb_NotifyChange(FILE_ACTION_ADDED,
2568                                          FILE_NOTIFY_CHANGE_FILE_NAME,
2569                                          dscp, lastNamep, NULL, TRUE);
2570                 if (!excl && code == CM_ERROR_EXISTS) {
2571                         /* not an exclusive create, and someone else tried
2572                          * creating it already, then we open it anyway.  We
2573                          * don't bother retrying after this, since if this next
2574                          * fails, that means that the file was deleted after we
2575                          * started this call.
2576                          */
2577                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2578                                          userp, &req, &scp);
2579                         if (code == 0) {
2580                                 if (trunc) {
2581                                         setAttr.mask = CM_ATTRMASK_LENGTH;
2582                                         setAttr.length.LowPart = 0;
2583                                         setAttr.length.HighPart = 0;
2584                                         code = cm_SetAttr(scp, &setAttr, userp,
2585                                                           &req);
2586                                 }
2587                         }       /* lookup succeeded */
2588                 }
2589         }
2590         
2591         /* we don't need this any longer */
2592         if (dscp) cm_ReleaseSCache(dscp);
2593
2594         if (code) {
2595                 /* something went wrong creating or truncating the file */
2596                 if (scp) cm_ReleaseSCache(scp);
2597                 cm_ReleaseUser(userp);
2598                 return code;
2599         }
2600         
2601         /* make sure we're about to open a file */
2602         if (scp->fileType != CM_SCACHETYPE_FILE) {
2603                 cm_ReleaseSCache(scp);
2604                 cm_ReleaseUser(userp);
2605                 return CM_ERROR_ISDIR;
2606         }
2607
2608         /* now all we have to do is open the file itself */
2609         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2610         osi_assert(fidp);
2611         
2612         /* save a pointer to the vnode */
2613         fidp->scp = scp;
2614         
2615         /* compute open mode */
2616         if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2617         if (openMode == 1 || openMode == 2)
2618                 fidp->flags |= SMB_FID_OPENWRITE;
2619
2620         smb_ReleaseFID(fidp);
2621         
2622         cm_Open(scp, 0, userp);
2623
2624         /* set inp->fid so that later read calls in same msg can find fid */
2625         inp->fid = fidp->fid;
2626         
2627         /* copy out remainder of the parms */
2628         parmSlot = 2;
2629         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2630         lock_ObtainMutex(&scp->mx);
2631         if (extraInfo) {
2632                 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2633                 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2634                 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2635                 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2636                 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2637                 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2638                 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2639                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2640                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2641         }
2642         /* and the final "always present" stuff */
2643         smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2644         /* next write out the "unique" ID */
2645         smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2646         smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2647         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2648         lock_ReleaseMutex(&scp->mx);
2649         smb_SetSMBDataLength(outp, 0);
2650
2651         osi_Log1(afsd_logp, "SMB OpenX opening fid %d", fidp->fid);
2652
2653         cm_ReleaseUser(userp);
2654         /* leave scp held since we put it in fidp->scp */
2655         return 0;
2656 }
2657
2658 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2659 {
2660         cm_req_t req;
2661         cm_user_t *userp;
2662         unsigned short fid;
2663         smb_fid_t *fidp;
2664         cm_scache_t *scp;
2665         unsigned char LockType;
2666         unsigned short NumberOfUnlocks, NumberOfLocks;
2667         unsigned long Timeout;
2668         char *op;
2669         LARGE_INTEGER LOffset, LLength;
2670         smb_waitingLock_t *waitingLock;
2671         void *lockp;
2672         long code;
2673         int i;
2674
2675         cm_InitReq(&req);
2676
2677         fid = smb_GetSMBParm(inp, 2);
2678         fid = smb_ChainFID(fid, inp);
2679
2680         fidp = smb_FindFID(vcp, fid, 0);
2681         if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2682                 return CM_ERROR_BADFD;
2683         }
2684         /* set inp->fid so that later read calls in same msg can find fid */
2685         inp->fid = fid;
2686
2687         userp = smb_GetUser(vcp, inp);
2688
2689         scp = fidp->scp;
2690
2691         lock_ObtainMutex(&scp->mx);
2692         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2693                          CM_SCACHESYNC_NEEDCALLBACK
2694                          | CM_SCACHESYNC_GETSTATUS
2695                          | CM_SCACHESYNC_LOCK);
2696         if (code) goto doneSync;
2697
2698         LockType = smb_GetSMBParm(inp, 3) & 0xff;
2699         Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2700         NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2701         NumberOfLocks = smb_GetSMBParm(inp, 7);
2702
2703         op = smb_GetSMBData(inp, NULL);
2704
2705         for (i=0; i<NumberOfUnlocks; i++) {
2706                 if (LockType & 0x10) {
2707                         /* Large Files */
2708                         LOffset.HighPart = *((LONG *)(op + 4));
2709                         LOffset.LowPart = *((DWORD *)(op + 8));
2710                         LLength.HighPart = *((LONG *)(op + 12));
2711                         LLength.LowPart = *((DWORD *)(op + 16));
2712                         op += 20;
2713                 }
2714                 else {
2715                         /* Not Large Files */
2716                         LOffset.HighPart = 0;
2717                         LOffset.LowPart = *((DWORD *)(op + 2));
2718                         LLength.HighPart = 0;
2719                         LLength.LowPart = *((DWORD *)(op + 6));
2720                         op += 10;
2721                 }
2722                 if (LargeIntegerNotEqualToZero(LOffset))
2723                         continue;
2724                 /* Do not check length -- length check done in cm_Unlock */
2725
2726                 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2727                 if (code) goto done;
2728         }
2729
2730         for (i=0; i<NumberOfLocks; i++) {
2731                 if (LockType & 0x10) {
2732                         /* Large Files */
2733                         LOffset.HighPart = *((LONG *)(op + 4));
2734                         LOffset.LowPart = *((DWORD *)(op + 8));
2735                         LLength.HighPart = *((LONG *)(op + 12));
2736                         LLength.LowPart = *((DWORD *)(op + 16));
2737                         op += 20;
2738                 }
2739                 else {
2740                         /* Not Large Files */
2741                         LOffset.HighPart = 0;
2742                         LOffset.LowPart = *((DWORD *)(op + 2));
2743                         LLength.HighPart = 0;
2744                         LLength.LowPart = *((DWORD *)(op + 6));
2745                         op += 10;
2746                 }
2747                 if (LargeIntegerNotEqualToZero(LOffset))
2748                         continue;
2749                 if (LargeIntegerLessThan(LOffset, scp->length))
2750                         continue;
2751
2752                 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2753                                 userp, &req, &lockp);
2754                 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2755                         /* Put on waiting list */
2756                         waitingLock = malloc(sizeof(smb_waitingLock_t));
2757                         waitingLock->vcp = vcp;
2758                         waitingLock->inp = smb_CopyPacket(inp);
2759                         waitingLock->outp = smb_CopyPacket(outp);
2760                         waitingLock->timeRemaining = Timeout;
2761                         waitingLock->lockp = lockp;
2762                         lock_ObtainWrite(&smb_globalLock);
2763                         osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2764                                  &waitingLock->q);
2765                         osi_Wakeup((long) &smb_allWaitingLocks);
2766                         lock_ReleaseWrite(&smb_globalLock);
2767                         /* don't send reply immediately */
2768                         outp->flags |= SMB_PACKETFLAG_NOSEND;
2769                 }
2770                 if (code) break;
2771         }
2772
2773         if (code) {
2774                 /* release any locks acquired before the failure */
2775         }
2776         else
2777                 smb_SetSMBDataLength(outp, 0);
2778 done:
2779         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2780 doneSync:
2781         lock_ReleaseMutex(&scp->mx);
2782         cm_ReleaseUser(userp);
2783         smb_ReleaseFID(fidp);
2784
2785         return code;
2786 }
2787
2788 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2789 {
2790         unsigned short fid;
2791         smb_fid_t *fidp;
2792         cm_scache_t *scp;
2793         long code;
2794         long searchTime;
2795         cm_user_t *userp;
2796         cm_req_t req;
2797
2798         cm_InitReq(&req);
2799
2800         fid = smb_GetSMBParm(inp, 0);
2801         fid = smb_ChainFID(fid, inp);
2802         
2803         fidp = smb_FindFID(vcp, fid, 0);
2804         if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2805                 return CM_ERROR_BADFD;
2806         }
2807         
2808         userp = smb_GetUser(vcp, inp);
2809         
2810         scp = fidp->scp;
2811         
2812         /* otherwise, stat the file */
2813         lock_ObtainMutex(&scp->mx);
2814         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2815                 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2816         if (code) goto done;
2817
2818         /* decode times.  We need a search time, but the response to this
2819          * call provides the date first, not the time, as returned in the
2820          * searchTime variable.  So we take the high-order bits first.
2821          */
2822         smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2823         smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff);   /* ctime */
2824         smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2825         smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff);   /* atime */
2826         smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2827         smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff);   /* mtime */
2828         smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2829         
2830         /* now handle file size and allocation size */
2831         smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff);          /* file size */
2832         smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2833         smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff);          /* alloc size */
2834         smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2835         
2836         /* file attribute */
2837         smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2838         
2839         /* and finalize stuff */
2840         smb_SetSMBDataLength(outp, 0);
2841         code = 0;
2842
2843 done:
2844         lock_ReleaseMutex(&scp->mx);
2845         cm_ReleaseUser(userp);
2846         smb_ReleaseFID(fidp);
2847         return code;
2848 }
2849
2850 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2851 {
2852         unsigned short fid;
2853         smb_fid_t *fidp;
2854         cm_scache_t *scp;
2855         long code;
2856         long searchTime;
2857         long unixTime;
2858         cm_user_t *userp;
2859         cm_attr_t attrs;
2860         cm_req_t req;
2861
2862         cm_InitReq(&req);
2863
2864         fid = smb_GetSMBParm(inp, 0);
2865         fid = smb_ChainFID(fid, inp);
2866         
2867         fidp = smb_FindFID(vcp, fid, 0);
2868         if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2869                 return CM_ERROR_BADFD;
2870         }
2871         
2872         userp = smb_GetUser(vcp, inp);
2873         
2874         scp = fidp->scp;
2875         
2876         /* now prepare to call cm_setattr.  This message only sets various times,
2877          * and AFS only implements mtime, and we'll set the mtime if that's
2878          * requested.  The others we'll ignore.
2879          */
2880         searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
2881         
2882         if (searchTime != 0) {
2883                 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
2884                 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
2885                 attrs.clientModTime = unixTime;
2886                 code = cm_SetAttr(scp, &attrs, userp, &req);
2887         }
2888         else code = 0;
2889
2890         cm_ReleaseUser(userp);
2891         smb_ReleaseFID(fidp);
2892         return code;
2893 }
2894
2895
2896 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2897 {
2898         osi_hyper_t offset;
2899         long count, finalCount;
2900         unsigned short fd;
2901         smb_fid_t *fidp;
2902         long code;
2903         cm_user_t *userp;
2904         char *op;
2905         
2906         fd = smb_GetSMBParm(inp, 2);
2907         count = smb_GetSMBParm(inp, 5);
2908         offset.HighPart = 0;    /* too bad */
2909         offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
2910         
2911         osi_Log3(afsd_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
2912                 fd, offset.LowPart, count);
2913         
2914         fd = smb_ChainFID(fd, inp);
2915         fidp = smb_FindFID(vcp, fd, 0);
2916         if (!fidp) {
2917                 return CM_ERROR_BADFD;
2918         }
2919         /* set inp->fid so that later read calls in same msg can find fid */
2920         inp->fid = fd;
2921
2922         if (fidp->flags & SMB_FID_IOCTL) {
2923                 return smb_IoctlV3Read(fidp, vcp, inp, outp);
2924         }
2925         
2926         userp = smb_GetUser(vcp, inp);
2927
2928         /* 0 and 1 are reserved for request chaining, were setup by our caller,
2929          * and will be further filled in after we return.
2930          */
2931         smb_SetSMBParm(outp, 2, 0);     /* remaining bytes, for pipes */
2932         smb_SetSMBParm(outp, 3, 0);     /* resvd */
2933         smb_SetSMBParm(outp, 4, 0);     /* resvd */
2934         smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
2935         /* fill in #6 when we have all the parameters' space reserved */
2936         smb_SetSMBParm(outp, 7, 0);     /* resv'd */
2937         smb_SetSMBParm(outp, 8, 0);     /* resv'd */
2938         smb_SetSMBParm(outp, 9, 0);     /* resv'd */
2939         smb_SetSMBParm(outp, 10, 0);    /* resv'd */
2940         smb_SetSMBParm(outp, 11, 0);    /* reserved */
2941
2942         /* get op ptr after putting in the parms, since otherwise we don't
2943          * know where the data really is.
2944          */
2945         op = smb_GetSMBData(outp, NULL);
2946         
2947         /* now fill in offset from start of SMB header to first data byte (to op) */
2948         smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
2949
2950         /* set the packet data length the count of the # of bytes */
2951         smb_SetSMBDataLength(outp, count);
2952
2953 #ifndef DJGPP
2954         code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
2955 #else /* DJGPP */
2956         code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
2957 #endif /* !DJGPP */
2958
2959         /* fix some things up */
2960         smb_SetSMBParm(outp, 5, finalCount);
2961         smb_SetSMBDataLength(outp, finalCount);
2962
2963         smb_ReleaseFID(fidp);
2964
2965         cm_ReleaseUser(userp);
2966         return code;
2967 }
2968         
2969 /*
2970  * Values for createDisp, copied from NTDDK.H
2971  *
2972  *  FILE_SUPERSEDE      0       (???)
2973  *  FILE_OPEN           1       (open)
2974  *  FILE_CREATE         2       (exclusive)
2975  *  FILE_OPEN_IF        3       (non-exclusive)
2976  *  FILE_OVERWRITE      4       (open & truncate, but do not create)
2977  *  FILE_OVERWRITE_IF   5       (open & truncate, or create)
2978  */
2979
2980 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2981 {
2982         char *pathp, *realPathp;
2983         long code;
2984         cm_space_t *spacep;
2985         cm_user_t *userp;
2986         cm_scache_t *dscp;              /* parent dir */
2987         cm_scache_t *scp;               /* file to create or open */
2988         cm_attr_t setAttr;
2989         char *lastNamep;
2990         unsigned short nameLength;
2991         unsigned int flags;
2992         unsigned int requestOpLock;
2993         unsigned int requestBatchOpLock;
2994         unsigned int mustBeDir;
2995         int realDirFlag;
2996         unsigned int desiredAccess;
2997         unsigned int extAttributes;
2998         unsigned int createDisp;
2999         unsigned int createOptions;
3000         int initialModeBits;
3001         unsigned short baseFid;
3002         smb_fid_t *baseFidp;
3003         smb_fid_t *fidp;
3004         cm_scache_t *baseDirp;
3005         unsigned short openAction;
3006         int parmSlot;
3007         long fidflags;
3008         FILETIME ft;
3009         LARGE_INTEGER sz;
3010         char *tidPathp;
3011         BOOL foundscp;
3012         cm_req_t req;
3013
3014         cm_InitReq(&req);
3015
3016         foundscp = FALSE;
3017         scp = NULL;
3018
3019         nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3020         flags = smb_GetSMBOffsetParm(inp, 3, 1)
3021                   | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3022         requestOpLock = flags & 0x02;
3023         requestBatchOpLock = flags & 0x04;
3024         mustBeDir = flags & 0x08;
3025
3026         /*
3027          * Why all of a sudden 32-bit FID?
3028          * We will reject all bits higher than 16.
3029          */
3030         if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3031                 return CM_ERROR_INVAL;
3032         baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3033         desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3034                           | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3035         extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3036                           | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3037         createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3038                         | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3039         createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3040                           | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3041
3042         /* mustBeDir is never set; createOptions directory bit seems to be
3043          * more important
3044          */
3045         if (createOptions & 1)
3046                 realDirFlag = 1;
3047         else if (createOptions & 0x40)
3048                 realDirFlag = 0;
3049         else
3050                 realDirFlag = -1;
3051
3052         /*
3053          * compute initial mode bits based on read-only flag in
3054          * extended attributes
3055          */
3056         initialModeBits = 0666;
3057         if (extAttributes & 1) initialModeBits &= ~0222;
3058
3059         pathp = smb_GetSMBData(inp, NULL);
3060         /* Sometimes path is not null-terminated, so we make a copy. */
3061         realPathp = malloc(nameLength+1);
3062         memcpy(realPathp, pathp, nameLength);
3063         realPathp[nameLength] = 0;
3064
3065         spacep = inp->spacep;
3066         smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3067
3068         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3069                 /* special case magic file name for receiving IOCTL requests
3070                  * (since IOCTL calls themselves aren't getting through).
3071                  */
3072                 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3073                 smb_SetupIoctlFid(fidp, spacep);
3074
3075                 /* set inp->fid so that later read calls in same msg can find fid */
3076                 inp->fid = fidp->fid;
3077
3078                 /* out parms */
3079                 parmSlot = 2;
3080                 smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
3081                 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3082                 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3083                 /* times */
3084                 memset(&ft, 0, sizeof(ft));
3085                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3086                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3087                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3088                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3089                 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3090                 sz.HighPart = 0x7fff; sz.LowPart = 0;
3091                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3092                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3093                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
3094                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
3095                 smb_SetSMBParmByte(outp, parmSlot, 0);  /* is a dir? */
3096                 smb_SetSMBDataLength(outp, 0);
3097
3098                 /* clean up fid reference */
3099                 smb_ReleaseFID(fidp);
3100                 free(realPathp);
3101                 return 0;
3102         }
3103
3104         userp = smb_GetUser(vcp, inp);
3105
3106         if (baseFid == 0) {
3107                 baseDirp = cm_rootSCachep;
3108                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3109         }
3110         else {
3111                 baseFidp = smb_FindFID(vcp, baseFid, 0);
3112                 baseDirp = baseFidp->scp;
3113                 tidPathp = NULL;
3114         }
3115
3116         /* compute open mode */
3117         fidflags = 0;
3118         if (desiredAccess & DELETE)
3119                 fidflags |= SMB_FID_OPENDELETE;
3120         if (desiredAccess & AFS_ACCESS_READ)
3121                 fidflags |= SMB_FID_OPENREAD;
3122         if (desiredAccess & AFS_ACCESS_WRITE)
3123                 fidflags |= SMB_FID_OPENWRITE;
3124
3125         dscp = NULL;
3126         code = 0;
3127         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3128                         userp, tidPathp, &req, &scp);
3129         if (code == 0) foundscp = TRUE;
3130         if (code != 0
3131             || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3132                 /* look up parent directory */
3133                 code = cm_NameI(baseDirp, spacep->data,
3134                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3135                                 userp, tidPathp, &req, &dscp);
3136
3137                 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3138
3139                 if (code) {
3140                         cm_ReleaseUser(userp);
3141                         free(realPathp);
3142                         return code;
3143                 }
3144
3145                 if (!lastNamep) lastNamep = realPathp;
3146                 else lastNamep++;
3147
3148                 if (!smb_IsLegalFilename(lastNamep))
3149                         return CM_ERROR_BADNTFILENAME;
3150
3151                 if (!foundscp) {
3152                         code = cm_Lookup(dscp, lastNamep,
3153                                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3154                                          userp, &req, &scp);
3155                         if (code && code != CM_ERROR_NOSUCHFILE) {
3156                                 cm_ReleaseSCache(dscp);
3157                                 cm_ReleaseUser(userp);
3158                                 free(realPathp);
3159                                 return code;
3160                         }
3161                 }
3162         }
3163         else {
3164                 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3165         }
3166
3167         /* if we get here, if code is 0, the file exists and is represented by
3168          * scp.  Otherwise, we have to create it.  The dir may be represented
3169          * by dscp, or we may have found the file directly.  If code is non-zero,
3170          * scp is NULL.
3171          */
3172         if (code == 0) {
3173                 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3174                                       &req);
3175                 if (code) {
3176                         if (dscp) cm_ReleaseSCache(dscp);
3177                         cm_ReleaseSCache(scp);
3178                         cm_ReleaseUser(userp);
3179                         free(realPathp);
3180                         return code;
3181                 }
3182
3183                 if (createDisp == 2) {
3184                         /* oops, file shouldn't be there */
3185                         if (dscp) cm_ReleaseSCache(dscp);
3186                         cm_ReleaseSCache(scp);
3187                         cm_ReleaseUser(userp);
3188                         free(realPathp);
3189                         return CM_ERROR_EXISTS;
3190                 }
3191
3192                 if (createDisp == 4
3193                     || createDisp == 5) {
3194                         setAttr.mask = CM_ATTRMASK_LENGTH;