c67e5ee4396de1eb8dcc69ffadd5813902ad1aa6
[openafs.git] / src / WINNT / afsd / smb_ioctl.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 #include <windows.h>
14 #include <stdlib.h>
15 #include <malloc.h>
16 #include <string.h>
17 #include <stdio.h>
18 #include <time.h>
19 #include <strsafe.h>
20
21 #include <osi.h>
22
23 #include "afsd.h"
24
25 #include "smb.h"
26
27 #include "cm_rpc.h"
28 #include "afs/afsrpc.h"
29 #include "afs/auth.h"
30
31 smb_ioctlProc_t *smb_ioctlProcsp[SMB_IOCTL_MAXPROCS];
32
33 void 
34 smb_InitIoctl(void)
35 {
36     int i;
37     for (i=0; i<SMB_IOCTL_MAXPROCS; i++)
38         smb_ioctlProcsp[i] = NULL;
39
40     smb_ioctlProcsp[VIOCGETAL] = smb_IoctlGetACL;
41     smb_ioctlProcsp[VIOC_FILE_CELL_NAME] = smb_IoctlGetFileCellName;
42     smb_ioctlProcsp[VIOCSETAL] = smb_IoctlSetACL;
43     smb_ioctlProcsp[VIOC_FLUSHVOLUME] = smb_IoctlFlushVolume;
44     smb_ioctlProcsp[VIOCFLUSH] = smb_IoctlFlushFile;
45     smb_ioctlProcsp[VIOCSETVOLSTAT] = smb_IoctlSetVolumeStatus;
46     smb_ioctlProcsp[VIOCGETVOLSTAT] = smb_IoctlGetVolumeStatus;
47     smb_ioctlProcsp[VIOCWHEREIS] = smb_IoctlWhereIs;
48     smb_ioctlProcsp[VIOC_AFS_STAT_MT_PT] = smb_IoctlStatMountPoint;
49     smb_ioctlProcsp[VIOC_AFS_DELETE_MT_PT] = smb_IoctlDeleteMountPoint;
50     smb_ioctlProcsp[VIOCCKSERV] = smb_IoctlCheckServers;
51     smb_ioctlProcsp[VIOC_GAG] = smb_IoctlGag;
52     smb_ioctlProcsp[VIOCCKBACK] = smb_IoctlCheckVolumes;
53     smb_ioctlProcsp[VIOCSETCACHESIZE] = smb_IoctlSetCacheSize;
54     smb_ioctlProcsp[VIOCGETCACHEPARMS] = smb_IoctlGetCacheParms;
55     smb_ioctlProcsp[VIOCGETCELL] = smb_IoctlGetCell;
56     smb_ioctlProcsp[VIOCNEWCELL] = smb_IoctlNewCell;
57     smb_ioctlProcsp[VIOC_GET_WS_CELL] = smb_IoctlGetWsCell;
58     smb_ioctlProcsp[VIOC_AFS_SYSNAME] = smb_IoctlSysName;
59     smb_ioctlProcsp[VIOC_GETCELLSTATUS] = smb_IoctlGetCellStatus;
60     smb_ioctlProcsp[VIOC_SETCELLSTATUS] = smb_IoctlSetCellStatus;
61     smb_ioctlProcsp[VIOC_SETSPREFS] = smb_IoctlSetSPrefs;
62     smb_ioctlProcsp[VIOC_GETSPREFS] = smb_IoctlGetSPrefs;
63     smb_ioctlProcsp[VIOC_STOREBEHIND] = smb_IoctlStoreBehind;
64     smb_ioctlProcsp[VIOC_AFS_CREATE_MT_PT] = smb_IoctlCreateMountPoint;
65     smb_ioctlProcsp[VIOC_TRACECTL] = smb_IoctlTraceControl;
66     smb_ioctlProcsp[VIOCSETTOK] = smb_IoctlSetToken;
67     smb_ioctlProcsp[VIOCGETTOK] = smb_IoctlGetTokenIter;
68     smb_ioctlProcsp[VIOCNEWGETTOK] = smb_IoctlGetToken;
69     smb_ioctlProcsp[VIOCDELTOK] = smb_IoctlDelToken;
70     smb_ioctlProcsp[VIOCDELALLTOK] = smb_IoctlDelAllToken;
71     smb_ioctlProcsp[VIOC_SYMLINK] = smb_IoctlSymlink;
72     smb_ioctlProcsp[VIOC_LISTSYMLINK] = smb_IoctlListlink;
73     smb_ioctlProcsp[VIOC_DELSYMLINK] = smb_IoctlDeletelink;
74     smb_ioctlProcsp[VIOC_MAKESUBMOUNT] = smb_IoctlMakeSubmount;
75     smb_ioctlProcsp[VIOC_GETRXKCRYPT] = smb_IoctlGetRxkcrypt;
76     smb_ioctlProcsp[VIOC_SETRXKCRYPT] = smb_IoctlSetRxkcrypt;
77     smb_ioctlProcsp[VIOC_ISSYMLINK] = smb_IoctlIslink;
78     smb_ioctlProcsp[VIOC_TRACEMEMDUMP] = smb_IoctlMemoryDump;
79     smb_ioctlProcsp[VIOC_ISSYMLINK] = smb_IoctlIslink;
80     smb_ioctlProcsp[VIOC_FLUSHALL] = smb_IoctlFlushAllVolumes;
81     smb_ioctlProcsp[VIOCGETFID] = smb_IoctlGetFid;
82     smb_ioctlProcsp[VIOCGETOWNER] = smb_IoctlGetOwner;
83     smb_ioctlProcsp[VIOC_RXSTAT_PROC] = smb_IoctlRxStatProcess;
84     smb_ioctlProcsp[VIOC_RXSTAT_PEER] = smb_IoctlRxStatPeer;
85     smb_ioctlProcsp[VIOC_UUIDCTL] = smb_IoctlUUIDControl;
86     smb_ioctlProcsp[VIOC_PATH_AVAILABILITY] = smb_IoctlPathAvailability;
87     smb_ioctlProcsp[VIOC_GETFILETYPE] = smb_IoctlGetFileType;
88     smb_ioctlProcsp[VIOC_VOLSTAT_TEST] = smb_IoctlVolStatTest;
89     smb_ioctlProcsp[VIOC_UNICODECTL] = smb_IoctlUnicodeControl;
90 }       
91
92 /* called to make a fid structure into an IOCTL fid structure */
93 void 
94 smb_SetupIoctlFid(smb_fid_t *fidp, cm_space_t *prefix)
95 {
96     smb_ioctl_t *iop;
97     cm_space_t *copyPrefix;
98
99     lock_ObtainMutex(&fidp->mx);
100     fidp->flags |= SMB_FID_IOCTL;
101     fidp->scp = &cm_data.fakeSCache;
102     cm_HoldSCache(fidp->scp);
103     if (fidp->ioctlp == NULL) {
104         iop = malloc(sizeof(*iop));
105         memset(iop, 0, sizeof(*iop));
106         fidp->ioctlp = iop;
107         iop->fidp = fidp;
108     }
109     if (prefix) {
110         copyPrefix = cm_GetSpace();
111         memcpy(copyPrefix->data, prefix->data, CM_UTILS_SPACESIZE);
112         fidp->ioctlp->prefix = copyPrefix;
113     }
114     lock_ReleaseMutex(&fidp->mx);
115 }
116
117 /* called when we receive a read call, does the send of the received data if
118  * this is the first read call.  This is the function that actually makes the
119  * call to the ioctl code.
120  */
121 afs_int32
122 smb_IoctlPrepareRead(struct smb_fid *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp)
123 {
124     afs_int32 opcode;
125     smb_ioctlProc_t *procp = NULL;
126     afs_int32 code;
127
128     if (ioctlp->ioctl.flags & CM_IOCTLFLAG_DATAIN) {
129         ioctlp->ioctl.flags &= ~CM_IOCTLFLAG_DATAIN;
130
131         /* do the call now, or fail if we didn't get an opcode, or
132          * enough of an opcode.
133          */
134         if (ioctlp->ioctl.inCopied < sizeof(afs_int32)) 
135             return CM_ERROR_INVAL;
136         memcpy(&opcode, ioctlp->ioctl.inDatap, sizeof(afs_int32));
137         ioctlp->ioctl.inDatap += sizeof(afs_int32);
138
139         osi_Log1(afsd_logp, "Ioctl opcode 0x%x", opcode);
140
141         /* check for opcode out of bounds */
142         if (opcode < 0 || opcode >= SMB_IOCTL_MAXPROCS)
143             return CM_ERROR_TOOBIG;
144
145         /* check for no such proc */
146         procp = smb_ioctlProcsp[opcode];
147         if (procp == NULL) 
148             return CM_ERROR_BADOP;
149
150         /* otherwise, make the call */
151         ioctlp->ioctl.outDatap += sizeof(afs_int32); /* reserve room for return code */
152         code = (*procp)(ioctlp, userp);
153
154         osi_Log1(afsd_logp, "Ioctl return code 0x%x", code);
155
156         /* copy in return code */
157         memcpy(ioctlp->ioctl.outAllocp, &code, sizeof(afs_int32));
158     }
159     return 0;
160 }
161
162 /* called when we receive a write call.  If this is the first write call after
163  * a series of reads (or the very first call), then we start a new call.
164  * We also ensure that things are properly initialized for the start of a call.
165  */
166 void 
167 smb_IoctlPrepareWrite(smb_fid_t *fidp, smb_ioctl_t *ioctlp)
168 {
169     /* make sure the buffer(s) are allocated */
170     if (!ioctlp->ioctl.inAllocp) 
171         ioctlp->ioctl.inAllocp = malloc(SMB_IOCTL_MAXDATA);
172     if (!ioctlp->ioctl.outAllocp)
173         ioctlp->ioctl.outAllocp = malloc(SMB_IOCTL_MAXDATA);
174
175     /* Fixes fs la problem.  We do a StrToOEM later and if this data isn't initialized we get memory issues. */
176     (void) memset(ioctlp->ioctl.inAllocp, 0, SMB_IOCTL_MAXDATA);
177     (void) memset(ioctlp->ioctl.outAllocp, 0, SMB_IOCTL_MAXDATA);
178
179     /* and make sure that we've reset our state for the new incoming request */
180     if (!(ioctlp->ioctl.flags & CM_IOCTLFLAG_DATAIN)) {
181         ioctlp->ioctl.inCopied = 0;
182         ioctlp->ioctl.outCopied = 0;
183         ioctlp->ioctl.inDatap = ioctlp->ioctl.inAllocp;
184         ioctlp->ioctl.outDatap = ioctlp->ioctl.outAllocp;
185         ioctlp->ioctl.flags |= CM_IOCTLFLAG_DATAIN;
186     }
187 }       
188
189 /* called from smb_ReceiveCoreRead when we receive a read on the ioctl fid */
190 afs_int32
191 smb_IoctlRead(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
192 {
193     smb_ioctl_t *iop;
194     long count;
195     afs_int32 leftToCopy;
196     char *op;
197     afs_int32 code;
198     cm_user_t *userp;
199
200     iop = fidp->ioctlp;
201     count = smb_GetSMBParm(inp, 1);
202     userp = smb_GetUserFromVCP(vcp, inp);
203
204     /* Identify tree */
205     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
206     if(code) {
207         cm_ReleaseUser(userp);
208         return CM_ERROR_NOSUCHPATH;
209     }
210
211     /* turn the connection around, if required */
212     code = smb_IoctlPrepareRead(fidp, iop, userp);
213
214     if (code) {
215         cm_ReleaseUser(userp);
216         return code;
217     }
218
219     leftToCopy = (afs_int32)((iop->ioctl.outDatap - iop->ioctl.outAllocp) - iop->ioctl.outCopied);
220     if (count > leftToCopy)
221         count = leftToCopy;
222
223     /* now set the parms for a read of count bytes */
224     smb_SetSMBParm(outp, 0, count);
225     smb_SetSMBParm(outp, 1, 0);
226     smb_SetSMBParm(outp, 2, 0);
227     smb_SetSMBParm(outp, 3, 0);
228     smb_SetSMBParm(outp, 4, 0);
229
230     smb_SetSMBDataLength(outp, count+3);
231
232     op = smb_GetSMBData(outp, NULL);
233     *op++ = 1;
234     *op++ = (char)(count & 0xff);
235     *op++ = (char)((count >> 8) & 0xff);
236
237     /* now copy the data into the response packet */
238     memcpy(op, iop->ioctl.outCopied + iop->ioctl.outAllocp, count);
239
240     /* and adjust the counters */
241     iop->ioctl.outCopied += count;
242
243     cm_ReleaseUser(userp);
244
245     return 0;
246 }
247
248 /* called from smb_ReceiveCoreWrite when we receive a write call on the IOCTL
249  * file descriptor.
250  */
251 afs_int32
252 smb_IoctlWrite(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
253 {
254     smb_ioctl_t *iop;
255     long count;
256     afs_int32 code;
257     char *op;
258     int inDataBlockCount;
259
260     code = 0;
261     count = smb_GetSMBParm(inp, 1);
262     iop = fidp->ioctlp;
263         
264     smb_IoctlPrepareWrite(fidp, iop);
265
266     op = smb_GetSMBData(inp, NULL);
267     op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
268         
269     if (count + iop->ioctl.inCopied > SMB_IOCTL_MAXDATA) {
270         code = CM_ERROR_TOOBIG;
271         goto done;
272     }
273         
274     /* copy data */
275     memcpy(iop->ioctl.inDatap + iop->ioctl.inCopied, op, count);
276         
277     /* adjust counts */
278     iop->ioctl.inCopied += count;
279
280   done:
281     /* return # of bytes written */
282     if (code == 0) {
283         smb_SetSMBParm(outp, 0, count);
284         smb_SetSMBDataLength(outp, 0);
285     }
286
287     return code;
288 }       
289
290 /* called from smb_ReceiveV3WriteX when we receive a write call on the IOCTL
291  * file descriptor.
292  */
293 afs_int32
294 smb_IoctlV3Write(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
295 {
296     smb_ioctl_t *iop;
297     long count;
298     afs_int32 code;
299     char *op;
300     int inDataBlockCount;
301
302     code = 0;
303     count = smb_GetSMBParm(inp, 10);
304     iop = fidp->ioctlp;
305
306     smb_IoctlPrepareWrite(fidp, iop);
307
308     op = inp->data + smb_GetSMBParm(inp, 11);
309     inDataBlockCount = count;
310
311     if (count + iop->ioctl.inCopied > SMB_IOCTL_MAXDATA) {
312         code = CM_ERROR_TOOBIG;
313         goto done;
314     }
315         
316     /* copy data */
317     memcpy(iop->ioctl.inDatap + iop->ioctl.inCopied, op, count);
318
319     /* adjust counts */
320     iop->ioctl.inCopied += count;
321
322   done:
323     /* return # of bytes written */
324     if (code == 0) {
325         smb_SetSMBParm(outp, 2, count);
326         smb_SetSMBParm(outp, 3, 0); /* reserved */
327         smb_SetSMBParm(outp, 4, 0); /* reserved */
328         smb_SetSMBParm(outp, 5, 0); /* reserved */
329         smb_SetSMBDataLength(outp, 0);
330     }
331
332     return code;
333 }       
334
335
336 /* called from V3 read to handle IOCTL descriptor reads */
337 afs_int32
338 smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
339 {
340     smb_ioctl_t *iop;
341     long count;
342     afs_int32 code;
343     long leftToCopy;
344     char *op;
345     cm_user_t *userp;
346     smb_user_t *uidp;
347
348     iop = fidp->ioctlp;
349     count = smb_GetSMBParm(inp, 5);
350         
351     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
352     userp = smb_GetUserFromUID(uidp);
353     osi_assertx(userp != NULL, "null cm_user_t");
354     iop->uidp = uidp;
355     if (uidp && uidp->unp) {
356         osi_Log3(afsd_logp, "Ioctl uid %d user %x name %S",
357                   uidp->userID, userp,
358                   osi_LogSaveClientString(afsd_logp, uidp->unp->name));
359     } else {
360         if (uidp)
361             osi_Log2(afsd_logp, "Ioctl uid %d user %x no name",
362                      uidp->userID, userp);
363         else
364             osi_Log1(afsd_logp, "Ioctl no uid user %x no name",
365                      userp);
366     }
367
368     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
369     if (code) {
370         if (uidp)
371             smb_ReleaseUID(uidp);
372         cm_ReleaseUser(userp);
373         return CM_ERROR_NOSUCHPATH;
374     }
375
376     code = smb_IoctlPrepareRead(fidp, iop, userp);
377     if (uidp) {
378         iop->uidp = 0;
379         smb_ReleaseUID(uidp);
380     }
381     if (code) {
382         cm_ReleaseUser(userp);
383         return code;
384     }
385
386     leftToCopy = (long)((iop->ioctl.outDatap - iop->ioctl.outAllocp) - iop->ioctl.outCopied);
387     if (count > leftToCopy) 
388         count = leftToCopy;
389         
390     /* 0 and 1 are reserved for request chaining, were setup by our caller,
391      * and will be further filled in after we return.
392      */
393     smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
394     smb_SetSMBParm(outp, 3, 0); /* resvd */
395     smb_SetSMBParm(outp, 4, 0); /* resvd */
396     smb_SetSMBParm(outp, 5, count);     /* # of bytes we're going to read */
397     /* fill in #6 when we have all the parameters' space reserved */
398     smb_SetSMBParm(outp, 7, 0); /* resv'd */
399     smb_SetSMBParm(outp, 8, 0); /* resv'd */
400     smb_SetSMBParm(outp, 9, 0); /* resv'd */
401     smb_SetSMBParm(outp, 10, 0);        /* resv'd */
402     smb_SetSMBParm(outp, 11, 0);        /* reserved */
403
404     /* get op ptr after putting in the last parm, since otherwise we don't
405      * know where the data really is.
406      */
407     op = smb_GetSMBData(outp, NULL);
408         
409     /* now fill in offset from start of SMB header to first data byte (to op) */
410     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
411
412     /* set the packet data length the count of the # of bytes */
413     smb_SetSMBDataLength(outp, count);
414         
415     /* now copy the data into the response packet */
416     memcpy(op, iop->ioctl.outCopied + iop->ioctl.outAllocp, count);
417
418     /* and adjust the counters */
419     iop->ioctl.outCopied += count;
420
421     /* and cleanup things */
422     cm_ReleaseUser(userp);
423
424     return 0;
425 }       
426
427 /* called from Read Raw to handle IOCTL descriptor reads */
428 afs_int32
429 smb_IoctlReadRaw(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
430                  smb_packet_t *outp)
431 {
432     smb_ioctl_t *iop;
433     long leftToCopy;
434     NCB *ncbp;
435     afs_int32 code;
436     cm_user_t *userp;
437     smb_user_t *uidp;
438
439     iop = fidp->ioctlp;
440
441     userp = smb_GetUserFromVCP(vcp, inp);
442
443     /* Log the user */
444     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
445     if (uidp && uidp->unp) {
446         osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s",
447                  uidp->userID, userp,
448                  osi_LogSaveClientString(afsd_logp, uidp->unp->name));
449     } else if (uidp) {
450         osi_Log2(afsd_logp, "Ioctl uid %d user %x no name",
451                  uidp->userID, userp);
452     } else {
453         osi_Log1(afsd_logp, "Ioctl no uid user %x no name",
454                   userp);
455     }
456     if (uidp) 
457         smb_ReleaseUID(uidp);
458
459     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
460     if (code) {
461         code = CM_ERROR_NOSUCHPATH;
462         goto done;
463     }
464
465     code = smb_IoctlPrepareRead(fidp, iop, userp);
466     if (code) {
467         goto done;
468     }
469
470     leftToCopy = (long)((iop->ioctl.outDatap - iop->ioctl.outAllocp) - iop->ioctl.outCopied);
471
472     ncbp = outp->ncbp;
473     memset((char *)ncbp, 0, sizeof(NCB));
474
475     ncbp->ncb_length = (unsigned short) leftToCopy;
476     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
477     ncbp->ncb_command = NCBSEND;
478     /*ncbp->ncb_lana_num = smb_LANadapter;*/
479     ncbp->ncb_lana_num = vcp->lana;
480
481     ncbp->ncb_buffer = iop->ioctl.outCopied + iop->ioctl.outAllocp;
482     code = Netbios(ncbp);
483
484     if (code != 0)
485         osi_Log1(afsd_logp, "ReadRaw send failure code %d", code);
486
487   done:
488     cm_ReleaseUser(userp);
489
490     return code;
491 }
492
493 /* parse the passed-in file name and do a namei on it.  If we fail,
494  * return an error code, otherwise return the vnode located in *scpp.
495  */
496 #define CM_PARSE_FLAG_LITERAL 1
497
498 afs_int32
499 smb_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
500                    cm_scache_t **scpp, afs_uint32 flags)
501 {
502     long code;
503     cm_scache_t  *substRootp = NULL;
504     cm_scache_t  *iscp = NULL;
505     char      *inPath;
506     clientchar_t *relativePath = NULL;
507     clientchar_t *lastComponent = NULL;
508     afs_uint32 follow = (flags & CM_PARSE_FLAG_LITERAL ? CM_FLAG_NOMOUNTCHASE : CM_FLAG_FOLLOW);
509
510     inPath = ioctlp->ioctl.inDatap;
511     /* setup the next data value for the caller to use */
512     ioctlp->ioctl.inDatap += (long)strlen(ioctlp->ioctl.inDatap) + 1;
513
514     osi_Log1(afsd_logp, "cm_ParseIoctlPath %s", osi_LogSaveString(afsd_logp,inPath));
515
516     /* This is usually the file name, but for StatMountPoint it is the path. */
517     /* ioctlp->ioctl.inDatap can be either of the form:
518      *    \path\.
519      *    \path\file
520      *    \\netbios-name\submount\path\.
521      *    \\netbios-name\submount\path\file
522      */
523
524     /* We do not perform path name translation on the ioctl path data
525      * because these paths were not translated by Windows through the
526      * file system API.  Therefore, they are not OEM characters but
527      * whatever the display character set is.
528      */
529
530     // TranslateExtendedChars(relativePath);
531
532     /* This is usually nothing, but for StatMountPoint it is the file name. */
533     // TranslateExtendedChars(ioctlp->ioctl.inDatap);
534
535     /* If the string starts with our UTF-8 prefix (which is the
536        sequence [ESC,'%','G'] as used by ISO-2022 to designate UTF-8
537        strings), we assume that the provided path is UTF-8.  Otherwise
538        we have to convert the string to UTF-8, since that is what we
539        want to use everywhere else.*/
540
541     if (memcmp(inPath, utf8_prefix, utf8_prefix_size) == 0) {
542         /* String is UTF-8 */
543         inPath += utf8_prefix_size;
544         ioctlp->ioctl.flags |= CM_IOCTLFLAG_USEUTF8;
545
546         relativePath = cm_Utf8ToClientStringAlloc(inPath, -1, NULL);
547     } else {
548         int cch;
549
550         /* Not a UTF-8 string */
551         /* TODO: If this is an OEM string, we should convert it to
552            UTF-8. */
553         if (smb_StoreAnsiFilenames) {
554             cch = cm_AnsiToClientString(inPath, -1, NULL, 0);
555 #ifdef DEBUG
556             osi_assert(cch > 0);
557 #endif
558             relativePath = malloc(cch * sizeof(clientchar_t));
559             cm_AnsiToClientString(inPath, -1, relativePath, cch);
560         } else {
561             TranslateExtendedChars(inPath);
562
563             cch = cm_OemToClientString(inPath, -1, NULL, 0);
564 #ifdef DEBUG
565             osi_assert(cch > 0);
566 #endif
567             relativePath = malloc(cch * sizeof(clientchar_t));
568             cm_OemToClientString(inPath, -1, relativePath, cch);
569         }
570     }
571
572     if (relativePath[0] == relativePath[1] &&
573         relativePath[1] == '\\' && 
574         !cm_ClientStrCmpNI(cm_NetbiosNameC, relativePath+2,
575                            cm_ClientStrLen(cm_NetbiosNameC))) 
576     {
577         clientchar_t shareName[256];
578         clientchar_t *sharePath;
579         int shareFound, i;
580
581         /* We may have found a UNC path. 
582          * If the first component is the NetbiosName,
583          * then throw out the second component (the submount)
584          * since it had better expand into the value of ioctl->tidPathp
585          */
586         clientchar_t * p;
587         p = relativePath + 2 + cm_ClientStrLen(cm_NetbiosNameC) + 1;                    /* buffer overflow vuln.? */
588         if ( !cm_ClientStrCmpNI(_C("all"),  p,  3) )
589             p += 4;
590
591         for (i = 0; *p && *p != '\\'; i++,p++ ) {
592             shareName[i] = *p;
593         }
594         p++;                    /* skip past trailing slash */
595         shareName[i] = 0;       /* terminate string */
596
597         shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
598         if ( shareFound ) {
599             /* we found a sharename, therefore use the resulting path */
600             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->wdata,
601                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
602                             userp, sharePath, reqp, &substRootp);
603             free(sharePath);
604             if (code) {
605                 osi_Log1(afsd_logp,"cm_ParseIoctlPath [1] code 0x%x", code);
606                 if (relativePath)
607                     free(relativePath);
608                 return code;
609             }
610
611             lastComponent = cm_ClientStrRChr(p,  '\\');
612             if (lastComponent && (lastComponent - p) > 1 &&
613                 cm_ClientStrLen(lastComponent) > 1) {
614                 *lastComponent = '\0';
615                 lastComponent++;
616
617                 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
618                                 userp, NULL, reqp, &iscp);
619                 if (code == 0)
620                     code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
621                                     userp, NULL, reqp, scpp);
622                 if (iscp)
623                     cm_ReleaseSCache(iscp);
624             } else {
625                 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
626                                 userp, NULL, reqp, scpp);
627             }
628             cm_ReleaseSCache(substRootp);
629             if (code) {
630                 osi_Log1(afsd_logp,"cm_ParseIoctlPath [2] code 0x%x", code);
631                 if (relativePath)
632                     free(relativePath);
633                 return code;
634             }
635         } else {
636             /* otherwise, treat the name as a cellname mounted off the afs root.
637              * This requires that we reconstruct the shareName string with 
638              * leading and trailing slashes.
639              */
640             p = relativePath + 2 + cm_ClientStrLen(cm_NetbiosNameC) + 1;
641             if ( !cm_ClientStrCmpNI(_C("all"),  p,  3) )
642                 p += 4;
643
644             shareName[0] = '/';
645             for (i = 1; *p && *p != '\\'; i++,p++ ) {
646                 shareName[i] = *p;
647             }
648             p++;                    /* skip past trailing slash */
649             shareName[i++] = '/';       /* add trailing slash */
650             shareName[i] = 0;       /* terminate string */
651
652
653             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->wdata,
654                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
655                             userp, shareName, reqp, &substRootp);
656             if (code) {
657                 osi_Log1(afsd_logp,"cm_ParseIoctlPath [3] code 0x%x", code);
658                 if (relativePath)
659                     free(relativePath);
660                 return code;
661             }
662
663             lastComponent = cm_ClientStrRChr(p,  '\\');
664             if (lastComponent && (lastComponent - p) > 1 &&
665                 cm_ClientStrLen(lastComponent) > 1) {
666                 *lastComponent = '\0';
667                 lastComponent++;
668
669                 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
670                                 userp, NULL, reqp, &iscp);
671                 if (code == 0)
672                     code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
673                                     userp, NULL, reqp, scpp);
674                 if (iscp)
675                     cm_ReleaseSCache(iscp);
676             } else {
677                 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
678                                 userp, NULL, reqp, scpp);
679             }
680
681             if (code) {
682                 cm_ReleaseSCache(substRootp);
683                 osi_Log1(afsd_logp,"cm_ParseIoctlPath code [4] 0x%x", code);
684                 if (relativePath)
685                     free(relativePath);
686                 return code;
687             }
688         }
689     } else {
690         code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->wdata,
691                          CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
692                          userp, ioctlp->tidPathp, reqp, &substRootp);
693         if (code) {
694             osi_Log1(afsd_logp,"cm_ParseIoctlPath [6] code 0x%x", code);
695             if (relativePath)
696                 free(relativePath);
697             return code;
698         }
699         
700         lastComponent = cm_ClientStrRChr(relativePath,  '\\');
701         if (lastComponent && (lastComponent - relativePath) > 1 &&
702             cm_ClientStrLen(lastComponent) > 1) {
703             *lastComponent = '\0';
704             lastComponent++;
705
706             code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
707                             userp, NULL, reqp, &iscp);
708             if (code == 0)
709                 code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
710                                 userp, NULL, reqp, scpp);
711             if (iscp)
712                 cm_ReleaseSCache(iscp);
713         } else {
714             code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | follow,
715                             userp, NULL, reqp, scpp);
716         }
717         if (code) {
718             cm_ReleaseSCache(substRootp);
719             osi_Log1(afsd_logp,"cm_ParseIoctlPath [7] code 0x%x", code);
720             if (relativePath)
721                 free(relativePath);
722             return code;
723         }
724     }
725
726     if (substRootp)
727         cm_ReleaseSCache(substRootp);
728
729     /* and return success */
730     osi_Log1(afsd_logp,"cm_ParseIoctlPath [8] code 0x%x", code);
731
732     if (relativePath)
733         free(relativePath);
734     return 0;
735 }
736
737
738
739 #define LEAF_SIZE 256
740 /* parse the passed-in file name and do a namei on its parent.  If we fail,
741  * return an error code, otherwise return the vnode located in *scpp.
742  */
743 afs_int32
744 smb_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
745                      cm_scache_t **scpp, clientchar_t *leafp)
746 {
747     long code;
748     clientchar_t tbuffer[1024];
749     clientchar_t *tp, *jp;
750     cm_scache_t *substRootp = NULL;
751     clientchar_t *inpathp = NULL;
752     char *inpathdatap;
753
754     inpathdatap = ioctlp->ioctl.inDatap;
755
756     /* If the string starts with our UTF-8 prefix (which is the
757        sequence [ESC,'%','G'] as used by ISO-2022 to designate UTF-8
758        strings), we assume that the provided path is UTF-8.  Otherwise
759        we have to convert the string to UTF-8, since that is what we
760        want to use everywhere else.*/
761
762     if (memcmp(inpathdatap, utf8_prefix, utf8_prefix_size) == 0) {
763
764         /* String is UTF-8 */
765         inpathdatap += utf8_prefix_size;
766         ioctlp->ioctl.flags |= CM_IOCTLFLAG_USEUTF8;
767
768         inpathp = cm_Utf8ToClientStringAlloc(inpathdatap, -1, NULL);
769     } else {
770         int cch;
771
772         /* Not a UTF-8 string */
773         /* TODO: If this is an OEM string, we should convert it to
774            UTF-8. */
775         if (smb_StoreAnsiFilenames) {
776             cch = cm_AnsiToClientString(inpathdatap, -1, NULL, 0);
777 #ifdef DEBUG
778             osi_assert(cch > 0);
779 #endif
780             inpathp = malloc(cch * sizeof(clientchar_t));
781             cm_AnsiToClientString(inpathdatap, -1, inpathp, cch);
782         } else {
783             TranslateExtendedChars(inpathdatap);
784
785             cch = cm_OemToClientString(inpathdatap, -1, NULL, 0);
786 #ifdef DEBUG
787             osi_assert(cch > 0);
788 #endif
789             inpathp = malloc(cch * sizeof(clientchar_t));
790             cm_OemToClientString(inpathdatap, -1, inpathp, cch);
791         }
792     }
793
794     cm_ClientStrCpy(tbuffer, lengthof(tbuffer), inpathp);
795     tp = cm_ClientStrRChr(tbuffer, '\\');
796     jp = cm_ClientStrRChr(tbuffer, '/');
797     if (!tp)
798         tp = jp;
799     else if (jp && (tp - tbuffer) < (jp - tbuffer))
800         tp = jp;
801     if (!tp) {
802         cm_ClientStrCpy(tbuffer, lengthof(tbuffer), _C("\\"));
803         if (leafp)
804             cm_ClientStrCpy(leafp, LEAF_SIZE, inpathp);
805     }
806     else {
807         *tp = 0;
808         if (leafp) 
809             cm_ClientStrCpy(leafp, LEAF_SIZE, tp+1);
810     }
811
812     free(inpathp);
813     inpathp = NULL;             /* We don't need this from this point on */
814
815     if (tbuffer[0] == tbuffer[1] &&
816         tbuffer[1] == '\\' && 
817         !cm_ClientStrCmpNI(cm_NetbiosNameC, tbuffer+2,
818                            cm_ClientStrLen(cm_NetbiosNameC))) 
819     {
820         clientchar_t shareName[256];
821         clientchar_t *sharePath;
822         int shareFound, i;
823
824         /* We may have found a UNC path. 
825          * If the first component is the NetbiosName,
826          * then throw out the second component (the submount)
827          * since it had better expand into the value of ioctl->tidPathp
828          */
829         clientchar_t * p;
830         p = tbuffer + 2 + cm_ClientStrLen(cm_NetbiosNameC) + 1;
831         if ( !cm_ClientStrCmpNI(_C("all"),  p,  3) )
832             p += 4;
833
834         for (i = 0; *p && *p != '\\'; i++,p++ ) {
835             shareName[i] = *p;
836         }
837         p++;                    /* skip past trailing slash */
838         shareName[i] = 0;       /* terminate string */
839
840         shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
841         if ( shareFound ) {
842             /* we found a sharename, therefore use the resulting path */
843             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->wdata,
844                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
845                             userp, sharePath, reqp, &substRootp);
846             free(sharePath);
847             if (code) return code;
848
849             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
850                             userp, NULL, reqp, scpp);
851             cm_ReleaseSCache(substRootp);
852             if (code) return code;
853         } else {
854             /* otherwise, treat the name as a cellname mounted off the afs root.
855              * This requires that we reconstruct the shareName string with 
856              * leading and trailing slashes.
857              */
858             p = tbuffer + 2 + cm_ClientStrLen(cm_NetbiosNameC) + 1;
859             if ( !cm_ClientStrCmpNI(_C("all"),  p,  3) )
860                 p += 4;
861
862             shareName[0] = '/';
863             for (i = 1; *p && *p != '\\'; i++,p++ ) {
864                 shareName[i] = *p;
865             }
866             p++;                    /* skip past trailing slash */
867             shareName[i++] = '/';       /* add trailing slash */
868             shareName[i] = 0;       /* terminate string */
869
870             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->wdata,
871                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
872                             userp, shareName, reqp, &substRootp);
873             if (code) return code;
874
875             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
876                             userp, NULL, reqp, scpp);
877             cm_ReleaseSCache(substRootp);
878             if (code) return code;
879         }
880     } else {
881         code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->wdata,
882                         CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
883                         userp, ioctlp->tidPathp, reqp, &substRootp);
884         if (code) return code;
885
886         code = cm_NameI(substRootp, tbuffer, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
887                         userp, NULL, reqp, scpp);
888         cm_ReleaseSCache(substRootp);
889         if (code) return code;
890     }
891
892     /* # of bytes of path */
893     code = (long)strlen(ioctlp->ioctl.inDatap) + 1;
894     ioctlp->ioctl.inDatap += code;
895
896     /* and return success */
897     return 0;
898 }
899
900 afs_int32 
901 smb_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
902 {
903     char *saveDataPtr;
904     char *tp;
905     int ticketLen;
906     char *ticket;
907     int ctSize;
908     struct ClearToken ct;
909     cm_cell_t *cellp;
910     cm_ucell_t *ucellp;
911     afs_uuid_t uuid;
912     int flags;
913     char sessionKey[8];
914     int release_userp = 0;
915     clientchar_t *uname = NULL;
916     clientchar_t *smbname = NULL;
917     clientchar_t *wdir = NULL;
918     afs_int32 code = 0;
919
920     saveDataPtr = ioctlp->ioctl.inDatap;
921
922     cm_SkipIoctlPath(&ioctlp->ioctl);
923
924     tp = ioctlp->ioctl.inDatap;
925
926     /* ticket length */
927     memcpy(&ticketLen, tp, sizeof(ticketLen));
928     tp += sizeof(ticketLen);
929     if (ticketLen < MINKTCTICKETLEN || ticketLen > MAXKTCTICKETLEN)
930         return CM_ERROR_INVAL;
931
932     /* remember ticket and skip over it for now */
933     ticket = tp;
934     tp += ticketLen;
935
936     /* clear token size */
937     memcpy(&ctSize, tp, sizeof(ctSize));
938     tp += sizeof(ctSize);
939     if (ctSize != sizeof(struct ClearToken))
940         return CM_ERROR_INVAL;
941
942     /* clear token */
943     memcpy(&ct, tp, ctSize);
944     tp += ctSize;
945     if (ct.AuthHandle == -1)
946         ct.AuthHandle = 999;    /* more rxvab compat stuff */
947
948     /* more stuff, if any */
949     if (ioctlp->ioctl.inCopied > tp - saveDataPtr) {
950         /* flags:  logon flag */
951         memcpy(&flags, tp, sizeof(int));
952         tp += sizeof(int);
953
954         /* cell name */
955         {
956             fschar_t * cellnamep;
957             clientchar_t * temp;
958
959             temp = cm_ParseIoctlStringAlloc(&ioctlp->ioctl, tp);
960             cellnamep = cm_ClientStringToFsStringAlloc(temp, -1, NULL);
961             cellp = cm_GetCell(cellnamep, CM_FLAG_CREATE | CM_FLAG_NOPROBE);
962             free(cellnamep);
963             free(temp);
964         }
965
966         if (!cellp) {
967             code = CM_ERROR_NOSUCHCELL;
968             goto done;
969         }
970         tp += strlen(tp) + 1;
971
972         /* user name */
973         uname = cm_ParseIoctlStringAlloc(&ioctlp->ioctl, tp);
974         tp += strlen(tp) + 1;
975
976         if (flags & PIOCTL_LOGON) {
977             /* SMB user name with which to associate tokens */
978             smbname = cm_ParseIoctlStringAlloc(&ioctlp->ioctl, tp);
979             osi_Log2(smb_logp,"cm_IoctlSetToken for user [%S] smbname [%S]",
980                      osi_LogSaveClientString(smb_logp,uname),
981                      osi_LogSaveClientString(smb_logp,smbname));
982             fprintf(stderr, "SMB name = %S\n", smbname);
983             tp += strlen(tp) + 1;
984         } else {
985             osi_Log1(smb_logp,"cm_IoctlSetToken for user [%S]",
986                      osi_LogSaveClientString(smb_logp, uname));
987         }
988
989         /* uuid */
990         memcpy(&uuid, tp, sizeof(uuid));
991         if (!cm_FindTokenEvent(uuid, sessionKey)) {
992             code = CM_ERROR_INVAL;
993             goto done;
994         }
995     } else {
996         cellp = cm_data.rootCellp;
997         osi_Log0(smb_logp,"cm_IoctlSetToken - no name specified");
998     }
999
1000     if (flags & PIOCTL_LOGON) {
1001         userp = smb_FindCMUserByName(smbname, ioctlp->fidp->vcp->rname,
1002                                      SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON);
1003         release_userp = 1;
1004     }
1005
1006     /* store the token */
1007     lock_ObtainMutex(&userp->mx);
1008     ucellp = cm_GetUCell(userp, cellp);
1009     osi_Log1(smb_logp,"cm_IoctlSetToken ucellp %lx", ucellp);
1010     ucellp->ticketLen = ticketLen;
1011     if (ucellp->ticketp)
1012         free(ucellp->ticketp);  /* Discard old token if any */
1013     ucellp->ticketp = malloc(ticketLen);
1014     memcpy(ucellp->ticketp, ticket, ticketLen);
1015     /*
1016      * Get the session key from the RPC, rather than from the pioctl.
1017      */
1018     /*
1019     memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
1020     */
1021     memcpy(ucellp->sessionKey.data, sessionKey, sizeof(sessionKey));
1022     ucellp->kvno = ct.AuthHandle;
1023     ucellp->expirationTime = ct.EndTimestamp;
1024     ucellp->gen++;
1025 #ifdef QUERY_AFSID
1026     ucellp->uid = ANONYMOUSID;
1027 #endif
1028     if (uname) {
1029         cm_ClientStringToFsString(uname, -1, ucellp->userName, MAXKTCNAMELEN);
1030 #ifdef QUERY_AFSID
1031         cm_UsernameToId(uname, ucellp, &ucellp->uid);
1032 #endif
1033     }
1034     ucellp->flags |= CM_UCELLFLAG_RXKAD;
1035     lock_ReleaseMutex(&userp->mx);
1036
1037     if (flags & PIOCTL_LOGON) {
1038         ioctlp->ioctl.flags |= CM_IOCTLFLAG_LOGON;
1039     }
1040
1041     cm_ResetACLCache(userp);
1042
1043   done:
1044     if (release_userp)
1045         cm_ReleaseUser(userp);
1046
1047     if (uname)
1048         free(uname);
1049
1050     if (smbname)
1051         free(smbname);
1052
1053     return code;
1054 }
1055
1056
1057
1058 afs_int32
1059 smb_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp)
1060 {
1061     smb_user_t *uidp = ioctlp->uidp;
1062
1063     if (uidp && uidp->unp) {
1064         int cch;
1065
1066         cch = cm_ClientStringToUtf8(uidp->unp->name,
1067                                     cm_ClientStrLen(uidp->unp->name),
1068
1069                                     ioctlp->ioctl.outDatap,
1070                                     (SMB_IOCTL_MAXDATA -
1071                                      (ioctlp->ioctl.outDatap - ioctlp->ioctl.outAllocp))
1072                                     / sizeof(cm_utf8char_t));
1073
1074         ioctlp->ioctl.outDatap += cch * sizeof(cm_utf8char_t);
1075     }
1076
1077     return 0;
1078 }
1079
1080 afs_int32 
1081 smb_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
1082 {
1083     cm_scache_t *scp;
1084     afs_int32 code;
1085     cm_req_t req;
1086     cm_ioctlQueryOptions_t *optionsp;
1087     afs_uint32 flags = 0;
1088
1089     smb_InitReq(&req);
1090
1091     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1092     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1093         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1094
1095     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1096         cm_fid_t fid;
1097         cm_SkipIoctlPath(&ioctlp->ioctl);
1098         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
1099                   optionsp->fid.vnode, optionsp->fid.unique);
1100         code = cm_GetSCache(&fid, &scp, userp, &req);
1101     } else {
1102         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1103     }
1104     if (code) 
1105         return code;
1106
1107     code = cm_IoctlGetACL(&ioctlp->ioctl, userp, scp, &req);
1108
1109     cm_ReleaseSCache(scp);
1110     return code;
1111 }
1112
1113 afs_int32 
1114 smb_IoctlSetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
1115 {
1116     cm_scache_t *scp;
1117     afs_int32 code;
1118     cm_req_t req;
1119     afs_uint32 flags = 0;
1120
1121     smb_InitReq(&req);
1122
1123     code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1124     if (code) 
1125         return code;
1126
1127     code = cm_IoctlSetACL(&ioctlp->ioctl, userp, scp, &req);
1128
1129     cm_ReleaseSCache(scp);
1130     return code;
1131 }
1132
1133 afs_int32
1134 smb_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp)
1135 {
1136     afs_int32 code;
1137     cm_scache_t *scp;
1138     cm_req_t req;
1139     cm_ioctlQueryOptions_t *optionsp;
1140     afs_uint32 flags = 0;
1141
1142     smb_InitReq(&req);
1143
1144     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1145     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1146         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1147
1148     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1149         cm_fid_t fid;
1150         cm_SkipIoctlPath(&ioctlp->ioctl);
1151         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
1152                   optionsp->fid.vnode, optionsp->fid.unique);
1153         code = cm_GetSCache(&fid, &scp, userp, &req);
1154     } else {
1155         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1156     }
1157     if (code) 
1158         return code;
1159
1160     code = cm_IoctlGetFileCellName(&ioctlp->ioctl, userp, scp, &req);
1161
1162     cm_ReleaseSCache(scp);
1163
1164     return code;
1165 }
1166
1167 afs_int32 
1168 smb_IoctlFlushAllVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
1169 {
1170     cm_req_t req;
1171
1172     smb_InitReq(&req);
1173
1174     cm_SkipIoctlPath(&ioctlp->ioctl);   /* we don't care about the path */
1175
1176     return cm_IoctlFlushAllVolumes(&ioctlp->ioctl, userp, &req);
1177 }
1178
1179 afs_int32 
1180 smb_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
1181 {
1182     afs_int32 code;
1183     cm_scache_t *scp;
1184     cm_req_t req;
1185     cm_ioctlQueryOptions_t *optionsp;
1186     afs_uint32 flags = 0;
1187
1188     smb_InitReq(&req);
1189
1190     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1191     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1192         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1193
1194     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1195         cm_fid_t fid;
1196         cm_SkipIoctlPath(&ioctlp->ioctl);
1197         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
1198                   optionsp->fid.vnode, optionsp->fid.unique);
1199         code = cm_GetSCache(&fid, &scp, userp, &req);
1200     } else {
1201         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1202     }
1203     if (code) 
1204         return code;
1205
1206     code = cm_IoctlFlushVolume(&ioctlp->ioctl, userp, scp, &req);
1207
1208     cm_ReleaseSCache(scp);
1209
1210     return code;
1211 }
1212
1213 afs_int32 
1214 smb_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
1215 {
1216     afs_int32 code;
1217     cm_scache_t *scp;
1218     cm_req_t req;
1219     cm_ioctlQueryOptions_t *optionsp;
1220     afs_uint32 flags = 0;
1221
1222     smb_InitReq(&req);
1223
1224     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1225     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1226         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1227
1228     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1229         cm_fid_t fid;
1230         cm_SkipIoctlPath(&ioctlp->ioctl);
1231         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1232                   optionsp->fid.vnode, optionsp->fid.unique);
1233         code = cm_GetSCache(&fid, &scp, userp, &req);
1234     } else {
1235         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1236     }
1237     if (code) 
1238         return code;
1239
1240     code = cm_IoctlFlushFile(&ioctlp->ioctl, userp, scp, &req);
1241
1242     cm_ReleaseSCache(scp);
1243     return code;
1244 }
1245
1246 afs_int32 
1247 smb_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1248 {
1249     afs_int32 code;
1250     cm_scache_t *scp;
1251     cm_req_t req;
1252
1253     smb_InitReq(&req);
1254
1255     code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, 0);
1256     if (code) return code;
1257
1258     code = cm_IoctlSetVolumeStatus(&ioctlp->ioctl, userp, scp, &req);
1259     cm_ReleaseSCache(scp);
1260
1261     return code;
1262 }
1263
1264 afs_int32 
1265 smb_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1266 {
1267     afs_int32 code;
1268     cm_scache_t *scp;
1269     cm_ioctlQueryOptions_t *optionsp;
1270     afs_uint32 flags = 0;
1271     cm_req_t req;
1272
1273     smb_InitReq(&req);
1274
1275     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1276     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1277         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1278
1279     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1280         cm_fid_t fid;
1281         cm_SkipIoctlPath(&ioctlp->ioctl);
1282         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
1283                   optionsp->fid.vnode, optionsp->fid.unique);
1284         code = cm_GetSCache(&fid, &scp, userp, &req);
1285     } else {
1286         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1287     }
1288     if (code) 
1289         return code;
1290
1291     code = cm_IoctlGetVolumeStatus(&ioctlp->ioctl, userp, scp, &req);
1292
1293     cm_ReleaseSCache(scp);
1294
1295     return code;
1296 }
1297
1298 afs_int32 
1299 smb_IoctlGetFid(struct smb_ioctl *ioctlp, struct cm_user *userp)
1300 {
1301     afs_int32 code;
1302     cm_scache_t *scp;
1303     cm_req_t req;
1304     cm_ioctlQueryOptions_t * optionsp;
1305     afs_uint32 flags = 0;
1306
1307     smb_InitReq(&req);
1308
1309     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1310     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1311         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1312
1313     code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1314     if (code) 
1315         return code;
1316
1317     code = cm_IoctlGetFid(&ioctlp->ioctl, userp, scp, &req);
1318
1319     cm_ReleaseSCache(scp);
1320
1321     return code;
1322 }
1323
1324 afs_int32 
1325 smb_IoctlGetFileType(struct smb_ioctl *ioctlp, struct cm_user *userp)
1326 {
1327     afs_int32 code;
1328     cm_scache_t *scp;
1329     cm_req_t req;
1330     cm_ioctlQueryOptions_t * optionsp;
1331     afs_uint32 flags = 0;
1332
1333     smb_InitReq(&req);
1334
1335     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1336     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1337         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1338
1339     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1340         cm_fid_t fid;
1341         cm_SkipIoctlPath(&ioctlp->ioctl);
1342         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
1343                   optionsp->fid.vnode, optionsp->fid.unique);
1344         code = cm_GetSCache(&fid, &scp, userp, &req);
1345     } else {
1346         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1347     }
1348     if (code) 
1349         return code;
1350
1351     code = cm_IoctlGetFileType(&ioctlp->ioctl, userp, scp, &req);
1352
1353     cm_ReleaseSCache(scp);
1354
1355     return code;
1356 }
1357
1358 afs_int32 
1359 smb_IoctlGetOwner(struct smb_ioctl *ioctlp, struct cm_user *userp)
1360 {
1361     afs_int32 code;
1362     cm_scache_t *scp;
1363     cm_req_t req;
1364     cm_ioctlQueryOptions_t *optionsp;
1365     afs_uint32 flags = 0;
1366
1367     smb_InitReq(&req);
1368
1369     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1370     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1371         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1372
1373     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1374         cm_fid_t fid;
1375         cm_SkipIoctlPath(&ioctlp->ioctl);
1376         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1377                   optionsp->fid.vnode, optionsp->fid.unique);
1378         code = cm_GetSCache(&fid, &scp, userp, &req);
1379     } else {
1380         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1381     }
1382     if (code) 
1383         return code;
1384
1385     code = cm_IoctlGetOwner(&ioctlp->ioctl, userp, scp, &req);
1386
1387     cm_ReleaseSCache(scp);
1388
1389     return code;
1390 }
1391
1392 afs_int32 
1393 smb_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1394 {
1395     afs_int32 code;
1396     cm_scache_t *scp;
1397     cm_req_t req;
1398     cm_ioctlQueryOptions_t *optionsp;
1399     afs_uint32 flags = 0;
1400
1401     smb_InitReq(&req);
1402
1403     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1404     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1405         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1406
1407     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1408         cm_fid_t fid;
1409         cm_SkipIoctlPath(&ioctlp->ioctl);
1410         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1411                   optionsp->fid.vnode, optionsp->fid.unique);
1412         code = cm_GetSCache(&fid, &scp, userp, &req);
1413     } else {
1414         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1415     }
1416     if (code) 
1417         return code;
1418
1419     code = cm_IoctlWhereIs(&ioctlp->ioctl, userp, scp, &req);
1420
1421     cm_ReleaseSCache(scp);
1422
1423     return code;
1424 }
1425
1426
1427 afs_int32 
1428 smb_IoctlStatMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
1429 {
1430     afs_int32 code;
1431     cm_scache_t *dscp;
1432     cm_req_t req;
1433
1434     smb_InitReq(&req);
1435
1436     code = smb_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
1437     if (code)
1438         return code;
1439
1440     code = cm_IoctlStatMountPoint(&ioctlp->ioctl, userp, dscp, &req);
1441
1442     cm_ReleaseSCache(dscp);
1443
1444     return code;
1445 }
1446
1447 afs_int32 
1448 smb_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
1449 {
1450     afs_int32 code;
1451     cm_scache_t *dscp;
1452     cm_req_t req;
1453
1454     smb_InitReq(&req);
1455
1456     code = smb_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
1457     if (code) 
1458         return code;
1459
1460     code = cm_IoctlDeleteMountPoint(&ioctlp->ioctl, userp, dscp, &req);
1461
1462     cm_ReleaseSCache(dscp);
1463
1464     return code;
1465 }
1466
1467 afs_int32 
1468 smb_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp)
1469 {
1470     cm_SkipIoctlPath(&ioctlp->ioctl);   /* we don't care about the path */
1471
1472     return cm_IoctlCheckServers(&ioctlp->ioctl, userp);
1473 }
1474
1475 afs_int32 
1476 smb_IoctlGag(struct smb_ioctl *ioctlp, struct cm_user *userp)
1477 {
1478     /* we don't print anything superfluous, so we don't support the gag call */
1479     return CM_ERROR_INVAL;
1480 }
1481
1482 afs_int32 
1483 smb_IoctlCheckVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
1484 {
1485     cm_SkipIoctlPath(&ioctlp->ioctl);
1486
1487     return cm_IoctlCheckVolumes(&ioctlp->ioctl, userp);
1488 }
1489
1490 afs_int32 smb_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp)
1491 {
1492     cm_SkipIoctlPath(&ioctlp->ioctl);
1493
1494     return cm_IoctlSetCacheSize(&ioctlp->ioctl, userp);
1495 }
1496
1497
1498 afs_int32 
1499 smb_IoctlTraceControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
1500 {
1501     cm_SkipIoctlPath(&ioctlp->ioctl);
1502        
1503     return cm_IoctlTraceControl(&ioctlp->ioctl, userp);
1504 }
1505
1506 afs_int32 
1507 smb_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp)
1508 {
1509     cm_SkipIoctlPath(&ioctlp->ioctl);
1510        
1511     return cm_IoctlGetCacheParms(&ioctlp->ioctl, userp);
1512 }
1513
1514 afs_int32 
1515 smb_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
1516 {
1517     cm_SkipIoctlPath(&ioctlp->ioctl);
1518
1519     return cm_IoctlGetCell(&ioctlp->ioctl, userp);
1520 }
1521
1522 afs_int32 
1523 smb_IoctlNewCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
1524 {
1525     cm_SkipIoctlPath(&ioctlp->ioctl);
1526
1527     return cm_IoctlNewCell(&ioctlp->ioctl, userp);
1528 }
1529
1530 afs_int32 
1531 smb_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp)
1532 {
1533     cm_SkipIoctlPath(&ioctlp->ioctl);
1534
1535     return cm_IoctlGetWsCell(&ioctlp->ioctl, userp);
1536 }
1537
1538 afs_int32 
1539 smb_IoctlSysName(struct smb_ioctl *ioctlp, struct cm_user *userp)
1540 {
1541     cm_SkipIoctlPath(&ioctlp->ioctl);
1542
1543     return cm_IoctlSysName(&ioctlp->ioctl, userp);
1544 }
1545
1546 afs_int32 
1547 smb_IoctlGetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1548 {
1549     cm_SkipIoctlPath(&ioctlp->ioctl);
1550
1551     return cm_IoctlGetCellStatus(&ioctlp->ioctl, userp);
1552 }
1553
1554 afs_int32 
1555 smb_IoctlSetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1556 {
1557     cm_SkipIoctlPath(&ioctlp->ioctl);
1558
1559     return cm_IoctlSetCellStatus(&ioctlp->ioctl, userp);
1560 }
1561
1562 afs_int32
1563 smb_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1564 {
1565     cm_SkipIoctlPath(&ioctlp->ioctl);
1566
1567     return cm_IoctlSetSPrefs(&ioctlp->ioctl, userp);
1568 }
1569
1570 afs_int32
1571 smb_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1572 {
1573     cm_SkipIoctlPath(&ioctlp->ioctl);
1574
1575     return cm_IoctlGetSPrefs(&ioctlp->ioctl, userp);
1576 }
1577
1578 afs_int32
1579 smb_IoctlStoreBehind(struct smb_ioctl *ioctlp, struct cm_user *userp)
1580 {
1581     /* we ignore default asynchrony since we only have one way
1582      * of doing this today.
1583      */
1584     return 0;
1585 }       
1586
1587 afs_int32
1588 smb_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
1589 {
1590     afs_int32 code;
1591     cm_scache_t *dscp;
1592     clientchar_t leaf[LEAF_SIZE];
1593     cm_req_t req;
1594
1595     smb_InitReq(&req);
1596         
1597     code = smb_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1598     if (code)
1599         return code;
1600
1601     code = cm_IoctlCreateMountPoint(&ioctlp->ioctl, userp, dscp, &req, leaf);
1602
1603     cm_ReleaseSCache(dscp);
1604     return code;
1605 }
1606
1607 afs_int32
1608 smb_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1609 {
1610     afs_int32 code;
1611     cm_scache_t *dscp;
1612     clientchar_t leaf[LEAF_SIZE];
1613     cm_req_t req;
1614
1615     smb_InitReq(&req);
1616
1617     code = smb_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1618     if (code) return code;
1619
1620     code = cm_IoctlSymlink(&ioctlp->ioctl, userp, dscp, &req, leaf);
1621
1622     cm_ReleaseSCache(dscp);
1623
1624     return code;
1625 }
1626
1627 afs_int32 
1628 smb_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1629 {
1630     afs_int32 code;
1631     cm_scache_t *dscp;
1632     cm_req_t req;
1633
1634     smb_InitReq(&req);
1635
1636     code = smb_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
1637     if (code) return code;
1638
1639     code = cm_IoctlListlink(&ioctlp->ioctl, userp, dscp, &req);
1640
1641     cm_ReleaseSCache(dscp);
1642     return code;
1643 }
1644
1645 afs_int32 
1646 smb_IoctlIslink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1647 {/*CHECK FOR VALID SYMLINK*/
1648     afs_int32 code;
1649     cm_scache_t *dscp;
1650     cm_req_t req;
1651
1652     smb_InitReq(&req);
1653
1654     code = smb_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
1655     if (code) return code;
1656
1657     code = cm_IoctlIslink(&ioctlp->ioctl, userp, dscp, &req);
1658
1659     cm_ReleaseSCache(dscp);
1660
1661     return code;
1662 }
1663
1664 afs_int32 
1665 smb_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1666 {
1667     afs_int32 code;
1668     cm_scache_t *dscp;
1669     cm_req_t req;
1670
1671     smb_InitReq(&req);
1672
1673     code = smb_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
1674     if (code) return code;
1675
1676     code = cm_IoctlDeletelink(&ioctlp->ioctl, userp, dscp, &req);
1677
1678     cm_ReleaseSCache(dscp);
1679
1680     return code;
1681 }
1682
1683 afs_int32 
1684 smb_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp)
1685 {
1686     cm_SkipIoctlPath(&ioctlp->ioctl);
1687
1688     return cm_IoctlGetTokenIter(&ioctlp->ioctl, userp);
1689 }
1690
1691 afs_int32
1692 smb_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
1693 {
1694     cm_SkipIoctlPath(&ioctlp->ioctl);
1695
1696     return cm_IoctlGetToken(&ioctlp->ioctl, userp);
1697 }
1698
1699
1700 afs_int32
1701 smb_IoctlDelToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
1702 {
1703     cm_SkipIoctlPath(&ioctlp->ioctl);
1704
1705     return cm_IoctlDelToken(&ioctlp->ioctl, userp);
1706 }
1707
1708
1709 afs_int32
1710 smb_IoctlDelAllToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
1711 {
1712     cm_SkipIoctlPath(&ioctlp->ioctl);
1713
1714     return cm_IoctlDelAllToken(&ioctlp->ioctl, userp);
1715 }
1716
1717
1718 afs_int32
1719 smb_IoctlMakeSubmount(struct smb_ioctl *ioctlp, struct cm_user *userp)
1720 {
1721     cm_SkipIoctlPath(&ioctlp->ioctl);
1722
1723     return cm_IoctlMakeSubmount(&ioctlp->ioctl, userp);
1724 }
1725
1726 afs_int32
1727 smb_IoctlGetRxkcrypt(struct smb_ioctl *ioctlp, struct cm_user *userp)
1728 {
1729     cm_SkipIoctlPath(&ioctlp->ioctl);
1730
1731     return cm_IoctlGetRxkcrypt(&ioctlp->ioctl, userp);
1732 }
1733
1734 afs_int32
1735 smb_IoctlSetRxkcrypt(struct smb_ioctl *ioctlp, struct cm_user *userp)
1736 {
1737     cm_SkipIoctlPath(&ioctlp->ioctl);
1738
1739     return cm_IoctlSetRxkcrypt(&ioctlp->ioctl, userp);
1740 }
1741
1742 afs_int32
1743 smb_IoctlRxStatProcess(struct smb_ioctl *ioctlp, struct cm_user *userp)
1744 {
1745     cm_SkipIoctlPath(&ioctlp->ioctl);
1746
1747     return cm_IoctlRxStatProcess(&ioctlp->ioctl, userp);
1748 }
1749
1750
1751 afs_int32
1752 smb_IoctlRxStatPeer(struct smb_ioctl *ioctlp, struct cm_user *userp)
1753 {
1754     cm_SkipIoctlPath(&ioctlp->ioctl);
1755
1756     return cm_IoctlRxStatPeer(&ioctlp->ioctl, userp);
1757 }
1758
1759 afs_int32
1760 smb_IoctlUnicodeControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
1761 {
1762     cm_SkipIoctlPath(&ioctlp->ioctl);
1763
1764     return cm_IoctlUnicodeControl(&ioctlp->ioctl, userp);
1765 }
1766
1767 afs_int32
1768 smb_IoctlUUIDControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
1769 {
1770     cm_SkipIoctlPath(&ioctlp->ioctl);
1771
1772     return cm_IoctlUUIDControl(&ioctlp->ioctl, userp);
1773 }
1774
1775
1776 afs_int32
1777 smb_IoctlMemoryDump(struct smb_ioctl *ioctlp, struct cm_user *userp)
1778 {
1779     cm_SkipIoctlPath(&ioctlp->ioctl);
1780
1781     return cm_IoctlMemoryDump(&ioctlp->ioctl, userp);
1782 }
1783
1784 afs_int32
1785 smb_IoctlPathAvailability(struct smb_ioctl *ioctlp, struct cm_user *userp)
1786 {
1787     afs_int32 code;
1788     cm_scache_t *scp;
1789     cm_req_t req;
1790     cm_ioctlQueryOptions_t *optionsp;
1791     afs_uint32 flags = 0;
1792
1793     smb_InitReq(&req);
1794
1795     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1796     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1797         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1798
1799     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1800         cm_fid_t fid;
1801         cm_SkipIoctlPath(&ioctlp->ioctl);
1802         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
1803                   optionsp->fid.vnode, optionsp->fid.unique);
1804         code = cm_GetSCache(&fid, &scp, userp, &req);
1805     } else {
1806         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1807     }
1808     if (code) 
1809         return code;
1810
1811     code = cm_IoctlPathAvailability(&ioctlp->ioctl, userp, scp, &req);
1812     cm_ReleaseSCache(scp);
1813     return code;
1814 }
1815
1816 afs_int32
1817 smb_IoctlVolStatTest(struct smb_ioctl *ioctlp, struct cm_user *userp)
1818 {
1819     cm_req_t req;
1820
1821     smb_InitReq(&req);
1822
1823     cm_SkipIoctlPath(&ioctlp->ioctl);
1824
1825     return cm_IoctlVolStatTest(&ioctlp->ioctl, userp, &req);
1826 }