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