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