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