windows-pioctl-refactoring-20080612
authorJeffrey Altman <jaltman@secure-endpoints.com>
Thu, 12 Jun 2008 15:54:23 +0000 (15:54 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Thu, 12 Jun 2008 15:54:23 +0000 (15:54 +0000)
LICENSE MIT

Refactor the pioctl handling to provide a layer of abstraction
between the smb server and the actual pioctl data processing.
This will permit a redirector pioctl layer to be implemented
on top of the core cm_ioctl interfaces.

The general approach is that there is a new cm_ioctl_t object
which is embedded withing a higher level abstraction object.
This object maintains all of the pioctl state processing and
removes any notion of file descriptors or other communication
channel parameters.

The cm_ioctl module maintains just about all of the core
functional processing except for SetToken which needs further
abstraction.  Path processing is now performed at the higher
layer and cm_ioctl functions accept cm_user_t, cm_scache_t,
and cm_req_t objects from the higher layer.

The smb_ioctl module performs all of the path translation
using smb server knowledge and passes the necessary objects
to the cm_ioctl module for processing.

src/WINNT/afsd/cm_ioctl.c
src/WINNT/afsd/cm_ioctl.h
src/WINNT/afsd/cm_user.c
src/WINNT/afsd/cm_vnodeops.c
src/WINNT/afsd/smb.c
src/WINNT/afsd/smb.h
src/WINNT/afsd/smb_iocons.h
src/WINNT/afsd/smb_ioctl.c
src/WINNT/afsd/smb_ioctl.h

index 5c95346..fcb20b0 100644 (file)
@@ -47,8 +47,8 @@
 #define PIOCTL_LOGON   0x1
 #define MAX_PATH 260
 
-static const char utf8_prefix[] = UTF8_PREFIX;
-static const int  utf8_prefix_size = sizeof(utf8_prefix) -  sizeof(char);
+const char utf8_prefix[] = UTF8_PREFIX;
+const int  utf8_prefix_size = sizeof(utf8_prefix) -  sizeof(char);
 
 osi_mutex_t cm_Afsdsbmt_Lock;
 
@@ -62,23 +62,34 @@ void cm_InitIoctl(void)
     lock_InitializeMutex(&cm_Afsdsbmt_Lock, "AFSDSBMT.INI Access Lock");
 }
 
-long cm_CleanFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
+/* 
+ * Utility function.  (Not currently in use.)
+ * This function forces all dirty buffers to the file server and 
+ * then discards the status info.
+ */
+afs_int32
+cm_CleanFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
 {
     long code;
 
     code = buf_CleanVnode(scp, userp, reqp);
-        
-    lock_ObtainWrite(&scp->rw);
-    cm_DiscardSCache(scp);
-    lock_ReleaseWrite(&scp->rw);
-
+    if (!code) {
+        lock_ObtainWrite(&scp->rw);
+        cm_DiscardSCache(scp);
+        lock_ReleaseWrite(&scp->rw);
+    }
     osi_Log2(afsd_logp,"cm_CleanFile scp 0x%x returns error: [%x]",scp, code);
     return code;
 }
 
-long cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
+/* 
+ * Utility function.  Used within this file.
+ * scp must be held but not locked.
+ */
+afs_int32
+cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
 {
-    long code;
+    afs_int32 code;
 
 #ifdef AFS_FREELANCE_CLIENT
     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
@@ -91,16 +102,21 @@ long cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
         
     lock_ObtainWrite(&scp->rw);
     cm_DiscardSCache(scp);
-
     lock_ReleaseWrite(&scp->rw);
 
     osi_Log2(afsd_logp,"cm_FlushFile scp 0x%x returns error: [%x]",scp, code);
     return code;
 }
 
-long cm_FlushParent(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
+/* 
+ * Utility function.  (Not currently in use)
+ * IoctlPath must be parsed or skipped prior to calling.
+ * scp must be held but not locked.
+ */
+afs_int32
+cm_FlushParent(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
 {
-    long code = 0;
+    afs_int32 code = 0;
     cm_scache_t * pscp;
   
     pscp = cm_FindSCacheParent(scp);
@@ -112,10 +128,13 @@ long cm_FlushParent(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
     return code;
 }
 
-
-long cm_FlushVolume(cm_user_t *userp, cm_req_t *reqp, afs_uint32 cell, afs_uint32 volume)
+/* 
+ * Utility function.  Used within this function.
+ */
+afs_int32
+cm_FlushVolume(cm_user_t *userp, cm_req_t *reqp, afs_uint32 cell, afs_uint32 volume)
 {
-    long code = 0;
+    afs_int32 code = 0;
     cm_scache_t *scp;
     int i;
 
@@ -146,10 +165,11 @@ long cm_FlushVolume(cm_user_t *userp, cm_req_t *reqp, afs_uint32 cell, afs_uint3
 }
 
 /*
- * cm_ResetACLCache -- invalidate ACL info for a user that has just
- *                     obtained or lost tokens
+ * Utility function.  Used within this file.
+ * Invalidate ACL info for a user that has just        obtained or lost tokens.
  */
-void cm_ResetACLCache(cm_user_t *userp)
+void 
+cm_ResetACLCache(cm_user_t *userp)
 {
     cm_scache_t *scp;
     int hash;
@@ -174,260 +194,33 @@ void cm_ResetACLCache(cm_user_t *userp)
  *
  *  If an extended character (80 - FF) is entered into a file
  *  or directory name in Windows, the character is translated
- *  into the OEM character map before being passed to us.  Why
- *  this occurs is unknown.  Our pioctl functions must match
+ *  into the OEM character map before being passed to us.
+ *  The pioctl functions must match
  *  this translation for paths given via our own commands (like
  *  fs).  If we do not do this, then we will try to perform an
  *  operation on a non-translated path, which we will fail to 
  *  find, since the path was created with the translated chars.
  *  This function performs the required translation.
+ *
+ *  OEM character code pages are used by the non-Unicode SMB
+ *  mode.  Do not use if the CM_IOCTLFLAG_USEUTF8 is set.
  */
-void TranslateExtendedChars(char *str)
+void 
+TranslateExtendedChars(char *str)
 {
     if (!str || !*str)
         return;
 
     CharToOem(str, str);
 }
-        
-/* parse the passed-in file name and do a namei on it.  If we fail,
- * return an error code, otherwise return the vnode located in *scpp.
- */
-#define CM_PARSE_FLAG_LITERAL 1
-
-long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
-       cm_scache_t **scpp, afs_uint32 flags)
-{
-    long code;
-    cm_scache_t *substRootp = NULL;
-    cm_scache_t *iscp = NULL;
-    char * relativePath;
-    char * lastComponent = NULL;
-    afs_uint32 follow = (flags & CM_PARSE_FLAG_LITERAL ? CM_FLAG_NOMOUNTCHASE : CM_FLAG_FOLLOW);
-    int free_path = FALSE;
-
-    relativePath = ioctlp->inDatap;
-    /* setup the next data value for the caller to use */
-    ioctlp->inDatap += (long)strlen(ioctlp->inDatap) + 1;;
-
-    osi_Log1(afsd_logp, "cm_ParseIoctlPath %s", osi_LogSaveString(afsd_logp,relativePath));
-
-    /* This is usually the file name, but for StatMountPoint it is the path. */
-    /* ioctlp->inDatap can be either of the form:
-     *    \path\.
-     *    \path\file
-     *    \\netbios-name\submount\path\.
-     *    \\netbios-name\submount\path\file
-     */
-
-       /* We do not perform path name translation on the ioctl path data 
-        * because these paths were not translated by Windows through the
-        * file system API.  Therefore, they are not OEM characters but 
-        * whatever the display character set is.
-        */
-
-    // TranslateExtendedChars(relativePath);
-
-    /* This is usually nothing, but for StatMountPoint it is the file name. */
-    // TranslateExtendedChars(ioctlp->inDatap);
-
-    /* If the string starts with our UTF-8 prefix (which is the
-       sequence [ESC,'%','G'] as used by ISO-2022 to designate UTF-8
-       strings), we assume that the provided path is UTF-8.  Otherwise
-       we have to convert the string to UTF-8, since that is what we
-       want to use everywhere else.*/
-
-    if (memcmp(relativePath, utf8_prefix, utf8_prefix_size) == 0) {
-        int len, normalized_len;
-        char * normalized_path;
-
-        /* String is UTF-8 */
-        relativePath += utf8_prefix_size;
-        ioctlp->flags |= SMB_IOCTLFLAG_USEUTF8;
-
-        len = (ioctlp->inDatap - relativePath);
-
-        normalized_len = cm_NormalizeUtf8String(relativePath, len, NULL, 0);
-
-        if (normalized_len > len) {
-            normalized_path = malloc(normalized_len);
-            free_path = TRUE;
-        } else {
-            normalized_path = relativePath;
-        }
-
-        cm_NormalizeUtf8String(relativePath, len, normalized_path, normalized_len);
-
-        if (normalized_path != relativePath)
-            relativePath = normalized_path;
-    } else {
-        /* Not a UTF-8 string */
-        /* TODO: If this is an OEM string, we should convert it to
-           UTF-8. */
-    }
-
-    if (relativePath[0] == relativePath[1] &&
-         relativePath[1] == '\\' && 
-         !_strnicmp(cm_NetbiosName,relativePath+2,strlen(cm_NetbiosName))) 
-    {
-        char shareName[256];
-        char *sharePath;
-        int shareFound, i;
-
-        /* We may have found a UNC path. 
-         * If the first component is the NetbiosName,
-         * then throw out the second component (the submount)
-         * since it had better expand into the value of ioctl->tidPathp
-         */
-        char * p;
-        p = relativePath + 2 + strlen(cm_NetbiosName) + 1;                     /* buffer overflow vuln.? */
-        if ( !_strnicmp("all", p, 3) )
-            p += 4;
 
-        for (i = 0; *p && *p != '\\'; i++,p++ ) {
-            shareName[i] = *p;
-        }
-        p++;                    /* skip past trailing slash */
-        shareName[i] = 0;       /* terminate string */
-
-        shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
-        if ( shareFound ) {
-            /* we found a sharename, therefore use the resulting path */
-            code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
-                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
-                             userp, sharePath, reqp, &substRootp);
-            free(sharePath);
-            if (code) {
-               osi_Log1(afsd_logp,"cm_ParseIoctlPath [1] code 0x%x", code);
-                if (free_path)
-                    free(relativePath);
-                return code;
-           }
-
-           lastComponent = strrchr(p, '\\');
-           if (lastComponent && (lastComponent - p) > 1 &&strlen(lastComponent) > 1) {
-               *lastComponent = '\0';
-               lastComponent++;
-
-               code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
-                                userp, NULL, reqp, &iscp);
-               if (code == 0)
-                   code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
-                                   userp, NULL, reqp, scpp);
-               if (iscp)
-                   cm_ReleaseSCache(iscp);
-           } else {
-               code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
-                               userp, NULL, reqp, scpp);
-           }
-           cm_ReleaseSCache(substRootp);
-            if (code) {
-               osi_Log1(afsd_logp,"cm_ParseIoctlPath [2] code 0x%x", code);
-                if (free_path)
-                    free(relativePath);
-                return code;
-           }
-        } else {
-            /* otherwise, treat the name as a cellname mounted off the afs root.
-             * This requires that we reconstruct the shareName string with 
-             * leading and trailing slashes.
-             */
-            p = relativePath + 2 + strlen(cm_NetbiosName) + 1;
-            if ( !_strnicmp("all", p, 3) )
-                p += 4;
-
-            shareName[0] = '/';
-            for (i = 1; *p && *p != '\\'; i++,p++ ) {
-                shareName[i] = *p;
-            }
-            p++;                    /* skip past trailing slash */
-            shareName[i++] = '/';      /* add trailing slash */
-            shareName[i] = 0;       /* terminate string */
-
-
-            code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
-                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
-                             userp, shareName, reqp, &substRootp);
-            if (code) {
-               osi_Log1(afsd_logp,"cm_ParseIoctlPath [3] code 0x%x", code);
-                if (free_path)
-                    free(relativePath);
-                return code;
-           }
-
-           lastComponent = strrchr(p, '\\');
-           if (lastComponent && (lastComponent - p) > 1 &&strlen(lastComponent) > 1) {
-               *lastComponent = '\0';
-               lastComponent++;
-
-               code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
-                                userp, NULL, reqp, &iscp);
-               if (code == 0)
-                   code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
-                                   userp, NULL, reqp, scpp);
-               if (iscp)
-                   cm_ReleaseSCache(iscp);
-           } else {
-               code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
-                               userp, NULL, reqp, scpp);
-           }
-
-           if (code) {
-               cm_ReleaseSCache(substRootp);
-               osi_Log1(afsd_logp,"cm_ParseIoctlPath code [4] 0x%x", code);
-                if (free_path)
-                    free(relativePath);
-                return code;
-           }
-        }
-    } else {
-        code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
-                         CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
-                         userp, ioctlp->tidPathp, reqp, &substRootp);
-        if (code) {
-           osi_Log1(afsd_logp,"cm_ParseIoctlPath [6] code 0x%x", code);
-            if (free_path)
-                free(relativePath);
-            return code;
-       }
-        
-       lastComponent = strrchr(relativePath, '\\');
-       if (lastComponent && (lastComponent - relativePath) > 1 && strlen(lastComponent) > 1) {
-           *lastComponent = '\0';
-           lastComponent++;
-
-           code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
-                            userp, NULL, reqp, &iscp);
-           if (code == 0)
-               code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
-                                userp, NULL, reqp, scpp);
-           if (iscp)
-               cm_ReleaseSCache(iscp);
-       } else {
-           code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | follow,
-                            userp, NULL, reqp, scpp);
-       }
-        if (code) {
-           cm_ReleaseSCache(substRootp);
-           osi_Log1(afsd_logp,"cm_ParseIoctlPath [7] code 0x%x", code);
-            if (free_path)
-                free(relativePath);
-            return code;
-       }
-    }
 
-    if (substRootp)
-       cm_ReleaseSCache(substRootp);
-
-    /* and return success */
-    osi_Log1(afsd_logp,"cm_ParseIoctlPath [8] code 0x%x", code);
-
-    if (free_path)
-        free(relativePath);
-    return 0;
-}
-
-void cm_SkipIoctlPath(smb_ioctl_t *ioctlp)
+/*
+ * Utility function.
+ * If the IoctlPath is not parsed then it must be skipped.
+ */
+void 
+cm_SkipIoctlPath(cm_ioctl_t *ioctlp)
 {
     size_t temp;
         
@@ -436,10 +229,10 @@ void cm_SkipIoctlPath(smb_ioctl_t *ioctlp)
 }       
 
 /* 
- * Must be called before cm_ParseIoctlPath or cm_SkipIoctlPath 
+ * Must be called before XXX_ParseIoctlPath or cm_SkipIoctlPath 
  */
-static cm_ioctlQueryOptions_t * 
-cm_IoctlGetQueryOptions(struct smb_ioctl *ioctlp, struct cm_user *userp)
+cm_ioctlQueryOptions_t * 
+cm_IoctlGetQueryOptions(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
     afs_uint32 pathlen = strlen(ioctlp->inDatap) + 1;
     char *p = ioctlp->inDatap + pathlen;
@@ -455,12 +248,12 @@ cm_IoctlGetQueryOptions(struct smb_ioctl *ioctlp, struct cm_user *userp)
 }
 
 /* 
- * Must be called after cm_ParseIoctlPath or cm_SkipIoctlPath
+ * Must be called after smb_ParseIoctlPath or cm_SkipIoctlPath
  * or any other time that ioctlp->inDatap points at the 
  * cm_ioctlQueryOptions_t object.
  */
-static void
-cm_IoctlSkipQueryOptions(struct smb_ioctl *ioctlp, struct cm_user *userp)
+void
+cm_IoctlSkipQueryOptions(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
     cm_ioctlQueryOptions_t * optionsp = (cm_ioctlQueryOptions_t *)ioctlp->inDatap;
     ioctlp->inDatap += optionsp->size;
@@ -473,7 +266,8 @@ cm_IoctlSkipQueryOptions(struct smb_ioctl *ioctlp, struct cm_user *userp)
  * easier (because we can always jump past the initial "/afs" to find
  * the AFS path that should be written into afsdsbmt.ini).
  */
-void cm_NormalizeAfsPath(char *outpathp, long outlen, char *inpathp)
+void 
+cm_NormalizeAfsPath(char *outpathp, long outlen, char *inpathp)
 {
     char *cp;
     char bslash_mountRoot[256];
@@ -504,199 +298,24 @@ void cm_NormalizeAfsPath(char *outpathp, long outlen, char *inpathp)
     }
 }
 
-#define LEAF_SIZE 256
-/* parse the passed-in file name and do a namei on its parent.  If we fail,
- * return an error code, otherwise return the vnode located in *scpp.
- */
-long cm_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
-                        cm_scache_t **scpp, char *leafp)
-{
-    long code;
-    char tbuffer[1024];
-    char *tp, *jp;
-    cm_scache_t *substRootp = NULL;
-    char *inpathp;
-    int free_path = FALSE;
-
-    inpathp = ioctlp->inDatap;
-
-    /* If the string starts with our UTF-8 prefix (which is the
-       sequence [ESC,'%','G'] as used by ISO-2022 to designate UTF-8
-       strings), we assume that the provided path is UTF-8.  Otherwise
-       we have to convert the string to UTF-8, since that is what we
-       want to use everywhere else.*/
-
-    if (memcmp(inpathp, utf8_prefix, utf8_prefix_size) == 0) {
-        int len, normalized_len;
-        char * normalized_path;
-
-        /* String is UTF-8 */
-        inpathp += utf8_prefix_size;
-        ioctlp->flags |= SMB_IOCTLFLAG_USEUTF8;
-
-        len = strlen(inpathp) + 1;
-
-        normalized_len = cm_NormalizeUtf8String(inpathp, len, NULL, 0);
-
-        if (normalized_len > len) {
-            normalized_path = malloc(normalized_len);
-            free_path = TRUE;
-        } else {
-            normalized_path = inpathp;
-        }
 
-        cm_NormalizeUtf8String(inpathp, len, normalized_path, normalized_len);
-
-        if (normalized_path != inpathp)
-            inpathp = normalized_path;
-    } else {
-        /* Not a UTF-8 string */
-        /* TODO: If this is an OEM string, we should convert it to
-           UTF-8. */
-    }
-
-    StringCbCopyA(tbuffer, sizeof(tbuffer), inpathp);
-    tp = strrchr(tbuffer, '\\');
-    jp = strrchr(tbuffer, '/');
-    if (!tp)
-        tp = jp;
-    else if (jp && (tp - tbuffer) < (jp - tbuffer))
-        tp = jp;
-    if (!tp) {
-        StringCbCopyA(tbuffer, sizeof(tbuffer), "\\");
-        if (leafp) 
-            StringCbCopyA(leafp, LEAF_SIZE, inpathp);
-    }
-    else {
-        *tp = 0;
-        if (leafp) 
-            StringCbCopyA(leafp, LEAF_SIZE, tp+1);
-    }   
-
-    if (free_path)
-        free(inpathp);
-    inpathp = NULL;             /* We don't need this from this point on */
-
-    if (free_path)
-        free(inpathp);
-    inpathp = NULL;             /* We don't need this from this point on */
-
-    if (tbuffer[0] == tbuffer[1] &&
-        tbuffer[1] == '\\' && 
-        !_strnicmp(cm_NetbiosName,tbuffer+2,strlen(cm_NetbiosName))) 
-    {
-        char shareName[256];
-        char *sharePath;
-        int shareFound, i;
-
-        /* We may have found a UNC path. 
-         * If the first component is the NetbiosName,
-         * then throw out the second component (the submount)
-         * since it had better expand into the value of ioctl->tidPathp
-         */
-        char * p;
-        p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
-        if ( !_strnicmp("all", p, 3) )
-            p += 4;
-
-        for (i = 0; *p && *p != '\\'; i++,p++ ) {
-            shareName[i] = *p;
-        }
-        p++;                    /* skip past trailing slash */
-        shareName[i] = 0;       /* terminate string */
-
-        shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
-        if ( shareFound ) {
-            /* we found a sharename, therefore use the resulting path */
-            code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
-                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
-                             userp, sharePath, reqp, &substRootp);
-            free(sharePath);
-            if (code) return code;
-
-            code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
-                             userp, NULL, reqp, scpp);
-           cm_ReleaseSCache(substRootp);
-            if (code) return code;
-        } else {
-            /* otherwise, treat the name as a cellname mounted off the afs root.
-             * This requires that we reconstruct the shareName string with 
-             * leading and trailing slashes.
-             */
-            p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
-            if ( !_strnicmp("all", p, 3) )
-                p += 4;
-
-            shareName[0] = '/';
-            for (i = 1; *p && *p != '\\'; i++,p++ ) {
-                shareName[i] = *p;
-            }
-            p++;                    /* skip past trailing slash */
-            shareName[i++] = '/';      /* add trailing slash */
-            shareName[i] = 0;       /* terminate string */
-
-            code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
-                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
-                             userp, shareName, reqp, &substRootp);
-            if (code) return code;
-
-            code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
-                            userp, NULL, reqp, scpp);
-           cm_ReleaseSCache(substRootp);
-            if (code) return code;
-        }
-    } else {
-        code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
-                        CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
-                        userp, ioctlp->tidPathp, reqp, &substRootp);
-        if (code) return code;
-
-        code = cm_NameI(substRootp, tbuffer, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
-                        userp, NULL, reqp, scpp);
-       cm_ReleaseSCache(substRootp);
-        if (code) return code;
-    }
-
-    /* # of bytes of path */
-    code = (long)strlen(ioctlp->inDatap) + 1;
-    ioctlp->inDatap += code;
-
-    /* and return success */
-    return 0;
-}
-
-long cm_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
+/* 
+ * VIOCGETAL internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * scp is held but not locked.
+ */
+afs_int32 
+cm_IoctlGetACL(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp)
 {
+    afs_int32 code;
     cm_conn_t *connp;
-    cm_scache_t *scp;
     AFSOpaque acl;
     AFSFetchStatus fileStatus;
     AFSVolSync volSync;
-    long code;
     AFSFid afid;
     int tlen;
-    cm_req_t req;
     struct rx_connection * callp;
-    cm_ioctlQueryOptions_t *optionsp;
-    afs_uint32 flags = 0;
-
-    cm_InitReq(&req);
-
-    optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
-    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
-        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
-
-    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
-        cm_fid_t fid;
-        cm_SkipIoctlPath(ioctlp);
-        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
-                  optionsp->fid.vnode, optionsp->fid.unique);
-        code = cm_GetSCache(&fid, &scp, userp, &req);
-    } else {
-        code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
-    }
-    if (code) 
-        return code;
 
     /* now make the get acl call */
 #ifdef AFS_FREELANCE_CLIENT
@@ -712,18 +331,19 @@ long cm_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
         do {
             acl.AFSOpaque_val = ioctlp->outDatap;
             acl.AFSOpaque_len = 0;
-            code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
-            if (code) continue;
+            code = cm_ConnFromFID(&scp->fid, userp, reqp, &connp);
+            if (code) 
+                continue;
 
             callp = cm_GetRxConn(connp);
             code = RXAFS_FetchACL(callp, &afid, &acl, &fileStatus, &volSync);
             rx_PutConnection(callp);
 
-        } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
-        code = cm_MapRPCError(code, &req);
-        cm_ReleaseSCache(scp);
+        } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync, NULL, NULL, code));
+        code = cm_MapRPCError(code, reqp);
 
-        if (code) return code;
+        if (code) 
+            return code;
     }
     /* skip over return data */
     tlen = (int)strlen(ioctlp->outDatap) + 1;
@@ -733,32 +353,18 @@ long cm_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
     return 0;
 }
 
-long cm_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp)
+
+/* 
+ * VIOC_FILE_CELL_NAME internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * scp is held but not locked.
+ */
+afs_int32 
+cm_IoctlGetFileCellName(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
 {
-    long code;
-    cm_scache_t *scp;
+    afs_int32 code;
     cm_cell_t *cellp;
-    cm_req_t req;
-    cm_ioctlQueryOptions_t *optionsp;
-    afs_uint32 flags = 0;
-
-    cm_InitReq(&req);
-
-    optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
-    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
-        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
-
-    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
-        cm_fid_t fid;
-        cm_SkipIoctlPath(ioctlp);
-        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
-                  optionsp->fid.vnode, optionsp->fid.unique);
-        code = cm_GetSCache(&fid, &scp, userp, &req);
-    } else {
-        code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
-    }
-    if (code) 
-        return code;
 
 #ifdef AFS_FREELANCE_CLIENT
     if ( cm_freelanceEnabled && 
@@ -781,27 +387,27 @@ long cm_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp)
             code = CM_ERROR_NOSUCHCELL;
     }
 
-    cm_ReleaseSCache(scp);
     return code;
 }
 
-long cm_IoctlSetACL(struct smb_ioctl *ioctlp, struct cm_user *userp)
+       
+/* 
+ * VIOCSETAL internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * scp is held but not locked.
+ */
+afs_int32 
+cm_IoctlSetACL(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
 {
+    afs_int32 code;
     cm_conn_t *connp;
-    cm_scache_t *scp;
     AFSOpaque acl;
     AFSFetchStatus fileStatus;
     AFSVolSync volSync;
-    long code;
     AFSFid fid;
-    cm_req_t req;
     struct rx_connection * callp;
 
-    cm_InitReq(&req);
-
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, 0);
-    if (code) return code;
-       
 #ifdef AFS_FREELANCE_CLIENT
     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
        code = CM_ERROR_NOACCESS;
@@ -815,39 +421,41 @@ long cm_IoctlSetACL(struct smb_ioctl *ioctlp, struct cm_user *userp)
         do {
             acl.AFSOpaque_val = ioctlp->inDatap;
             acl.AFSOpaque_len = (u_int)strlen(ioctlp->inDatap)+1;
-            code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
-            if (code) continue;
+            code = cm_ConnFromFID(&scp->fid, userp, reqp, &connp);
+            if (code) 
+                continue;
 
             callp = cm_GetRxConn(connp);
             code = RXAFS_StoreACL(callp, &fid, &acl, &fileStatus, &volSync);
             rx_PutConnection(callp);
 
-        } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
-        code = cm_MapRPCError(code, &req);
+        } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync, NULL, NULL, code));
+        code = cm_MapRPCError(code, reqp);
 
         /* invalidate cache info, since we just trashed the ACL cache */
         lock_ObtainWrite(&scp->rw);
         cm_DiscardSCache(scp);
         lock_ReleaseWrite(&scp->rw);
     }
-    cm_ReleaseSCache(scp);
 
     return code;
 }
 
-
-
-long cm_IoctlFlushAllVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_FLUSHALL internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32 
+cm_IoctlFlushAllVolumes(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
-    long code;
+    afs_int32 code;
     cm_scache_t *scp;
     int i;
     cm_req_t req;
 
     cm_InitReq(&req);
 
-    cm_SkipIoctlPath(ioctlp);  /* we don't care about the path */
-
     lock_ObtainWrite(&cm_scacheLock);
     for (i=0; i<cm_data.scacheHashTableSize; i++) {
         for (scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp) {
@@ -865,33 +473,18 @@ long cm_IoctlFlushAllVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return code;
 }
 
-long cm_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_FLUSHVOLUME internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * scp is held but not locked.
+ */
+afs_int32 
+cm_IoctlFlushVolume(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
 {
-    long code;
-    cm_scache_t *scp;
-    unsigned long volume;
-    unsigned long cell;
-    cm_req_t req;
-    cm_ioctlQueryOptions_t *optionsp;
-    afs_uint32 flags = 0;
-
-    cm_InitReq(&req);
-
-    optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
-    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
-        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
-
-    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
-        cm_fid_t fid;
-        cm_SkipIoctlPath(ioctlp);
-        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
-                  optionsp->fid.vnode, optionsp->fid.unique);
-        code = cm_GetSCache(&fid, &scp, userp, &req);
-    } else {
-        code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
-    }
-    if (code) 
-        return code;
+    afs_int32 code;
+    afs_uint32 volume;
+    afs_uint32 cell;
 
 #ifdef AFS_FREELANCE_CLIENT
     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
@@ -901,38 +494,21 @@ long cm_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
     {
         volume = scp->fid.volume;
         cell = scp->fid.cell;
-        cm_ReleaseSCache(scp);
-
-        code = cm_FlushVolume(userp, &req, cell, volume);
+        code = cm_FlushVolume(userp, reqp, cell, volume);
     }
     return code;
 }
 
-long cm_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOCFLUSH internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * scp is held but not locked.
+ */
+afs_int32 
+cm_IoctlFlushFile(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
 {
-    long code;
-    cm_scache_t *scp;
-    cm_req_t req;
-    cm_ioctlQueryOptions_t *optionsp;
-    afs_uint32 flags = 0;
-
-    cm_InitReq(&req);
-
-    optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
-    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
-        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
-
-    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
-        cm_fid_t fid;
-        cm_SkipIoctlPath(ioctlp);
-        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
-                  optionsp->fid.vnode, optionsp->fid.unique);
-        code = cm_GetSCache(&fid, &scp, userp, &req);
-    } else {
-        code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
-    }
-    if (code) 
-        return code;
+    afs_int32 code;
 
 #ifdef AFS_FREELANCE_CLIENT
     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
@@ -940,35 +516,34 @@ long cm_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
     } else
 #endif
     {
-        cm_FlushFile(scp, userp, &req);
+        cm_FlushFile(scp, userp, reqp);
     }
-    cm_ReleaseSCache(scp);
-
     return 0;
 }
 
-long cm_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
+
+/* 
+ * VIOCSETVOLSTAT internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * scp is held but not locked.
+ */
+afs_int32 
+cm_IoctlSetVolumeStatus(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
 {
-    cm_scache_t *scp;
+    afs_int32 code;
     char volName[32];
     char offLineMsg[256];
     char motd[256];
     cm_conn_t *tcp;
-    long code;
     AFSFetchVolumeStatus volStat;
     AFSStoreVolumeStatus storeStat;
     cm_volume_t *tvp;
     char *cp;
     cm_cell_t *cellp;
-    cm_req_t req;
     struct rx_connection * callp;
     int len;
 
-    cm_InitReq(&req);
-
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, 0);
-    if (code) return code;
-
 #ifdef AFS_FREELANCE_CLIENT
     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
        code = CM_ERROR_NOACCESS;
@@ -978,17 +553,14 @@ long cm_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
         cellp = cm_FindCellByID(scp->fid.cell, 0);
         osi_assertx(cellp, "null cm_cell_t");
 
-        if (scp->flags & CM_SCACHEFLAG_RO) {
-            cm_ReleaseSCache(scp);
+        if (scp->flags & CM_SCACHEFLAG_RO)
             return CM_ERROR_READONLY;
-        }
 
-        code = cm_FindVolumeByID(cellp, scp->fid.volume, userp, &req, 
+        code = cm_FindVolumeByID(cellp, scp->fid.volume, userp, reqp, 
                                  CM_GETVOL_FLAG_CREATE, &tvp);
-        if (code) {
-            cm_ReleaseSCache(scp);
+        if (code) 
             return code;
-        }
+
         cm_PutVolume(tvp);
 
         /* Copy the junk out, using cp as a roving pointer. */
@@ -1017,23 +589,22 @@ long cm_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
         }
 
         do {
-            code = cm_ConnFromFID(&scp->fid, userp, &req, &tcp);
-            if (code) continue;
+            code = cm_ConnFromFID(&scp->fid, userp, reqp, &tcp);
+            if (code)
+                continue;
 
             callp = cm_GetRxConn(tcp);
             code = RXAFS_SetVolumeStatus(callp, scp->fid.volume,
                                           &storeStat, volName, offLineMsg, motd);
             rx_PutConnection(callp);
 
-        } while (cm_Analyze(tcp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
-        code = cm_MapRPCError(code, &req);
+        } while (cm_Analyze(tcp, userp, reqp, &scp->fid, NULL, NULL, NULL, code));
+        code = cm_MapRPCError(code, reqp);
     }
     
     /* return on failure */
-    cm_ReleaseSCache(scp);
-    if (code) {
+    if (code)
         return code;
-    }
 
     /* we are sending parms back to make compat. with prev system.  should
      * change interface later to not ask for current status, just set
@@ -1055,41 +626,27 @@ long cm_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return 0;
 }       
 
-long cm_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
+
+/* 
+ * VIOCGETVOLSTAT internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * scp is held but not locked.
+ */
+afs_int32 
+cm_IoctlGetVolumeStatus(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
 {
-    char volName[32];
-    cm_scache_t *scp;
-    char offLineMsg[256];
-    char motd[256];
+    afs_int32 code;
+    char volName[32]="(unknown)";
+    char offLineMsg[256]="server temporarily inaccessible";
+    char motd[256]="server temporarily inaccessible";
     cm_conn_t *connp;
-    register long code;
     AFSFetchVolumeStatus volStat;
-    register char *cp;
+    char *cp;
     char *Name;
     char *OfflineMsg;
     char *MOTD;
-    cm_req_t req;
     struct rx_connection * callp;
-    cm_ioctlQueryOptions_t *optionsp;
-    afs_uint32 flags = 0;
-
-    cm_InitReq(&req);
-
-    optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
-    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
-        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
-
-    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
-        cm_fid_t fid;
-        cm_SkipIoctlPath(ioctlp);
-        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
-                  optionsp->fid.vnode, optionsp->fid.unique);
-        code = cm_GetSCache(&fid, &scp, userp, &req);
-    } else {
-        code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
-    }
-    if (code) 
-        return code;
 
 #ifdef AFS_FREELANCE_CLIENT
     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
@@ -1109,7 +666,7 @@ long cm_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
        OfflineMsg = offLineMsg;
        MOTD = motd;
        do {
-           code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
+           code = cm_ConnFromFID(&scp->fid, userp, reqp, &connp);
            if (code) continue;
 
            callp = cm_GetRxConn(connp);
@@ -1117,12 +674,12 @@ long cm_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
                                         &volStat, &Name, &OfflineMsg, &MOTD);
            rx_PutConnection(callp);
 
-       } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
-       code = cm_MapRPCError(code, &req);
+       } while (cm_Analyze(connp, userp, reqp, &scp->fid, NULL, NULL, NULL, code));
+       code = cm_MapRPCError(code, reqp);
     }
 
-    cm_ReleaseSCache(scp);
-    if (code) return code;
+    if (code) 
+        return code;
 
     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
     cp = ioctlp->outDatap;
@@ -1141,24 +698,17 @@ long cm_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return 0;
 }
 
-long cm_IoctlGetFid(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOCGETFID internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * scp is held but not locked.
+ */
+afs_int32 
+cm_IoctlGetFid(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
 {
-    cm_scache_t *scp;
-    register long code;
-    register char *cp;
+    char *cp;
     cm_fid_t fid;
-    cm_req_t req;
-    cm_ioctlQueryOptions_t * optionsp;
-    afs_uint32 flags = 0;
-
-    cm_InitReq(&req);
-
-    optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
-    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
-        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
-
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
-    if (code) return code;
 
     memset(&fid, 0, sizeof(cm_fid_t));
     fid.cell   = scp->fid.cell;
@@ -1166,8 +716,6 @@ long cm_IoctlGetFid(struct smb_ioctl *ioctlp, struct cm_user *userp)
     fid.vnode  = scp->fid.vnode;
     fid.unique = scp->fid.unique;
 
-    cm_ReleaseSCache(scp);
-
     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
     cp = ioctlp->outDatap;
     memcpy(cp, (char *)&fid, sizeof(cm_fid_t));
@@ -1179,128 +727,97 @@ long cm_IoctlGetFid(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return 0;
 }
 
-long cm_IoctlGetFileType(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_GETFILETYPE internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * scp is held but not locked.
+ */
+afs_int32 
+cm_IoctlGetFileType(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
 {
-    cm_scache_t *scp;
-    register long code;
-    register char *cp;
+    afs_int32 code = 0;
+    char *cp;
     afs_uint32 fileType = 0;
-    cm_req_t req;
-    cm_ioctlQueryOptions_t * optionsp;
-    afs_uint32 flags = 0;
-
-    cm_InitReq(&req);
-
-    optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
-    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
-        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
 
-    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
-        cm_fid_t fid;
-        cm_SkipIoctlPath(ioctlp);
-        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
-                  optionsp->fid.vnode, optionsp->fid.unique);
-        code = cm_GetSCache(&fid, &scp, userp, &req);
-    } else {
-        code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    if (scp->fileType == 0) {
+        lock_ObtainWrite(&scp->rw);
+        code = cm_SyncOp(scp, NULL, userp, reqp, 0,
+                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        if (code == 0)
+            cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        lock_ReleaseWrite(&scp->rw);
     }
-    if (code) 
-        return code;
-
-    fileType = scp->fileType;
-    cm_ReleaseSCache(scp);
 
-    /* Copy all this junk into msg->im_data, keeping track of the lengths. */
-    cp = ioctlp->outDatap;
-    memcpy(cp, (char *)&fileType, sizeof(fileType));
-    cp += sizeof(fileType);
+    if (code == 0) {
+        fileType = scp->fileType;
 
-    /* return new size */
-    ioctlp->outDatap = cp;
+        /* Copy all this junk into msg->im_data, keeping track of the lengths. */
+        cp = ioctlp->outDatap;
+        memcpy(cp, (char *)&fileType, sizeof(fileType));
+        cp += sizeof(fileType);
 
-    return 0;
+        /* return new size */
+        ioctlp->outDatap = cp;
+    }
+    return code;
 }
 
-long cm_IoctlGetOwner(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOCGETOWNER internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * scp is held but not locked.
+ */
+afs_int32 
+cm_IoctlGetOwner(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
 {
-    cm_scache_t *scp;
-    register long code;
-    register char *cp;
-    cm_req_t req;
-    cm_ioctlQueryOptions_t *optionsp;
-    afs_uint32 flags = 0;
+    afs_int32 code = 0;
+    char *cp;
 
-    cm_InitReq(&req);
+    lock_ObtainWrite(&scp->rw);
+    code = cm_SyncOp(scp, NULL, userp, reqp, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code == 0)
+        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&scp->rw);
 
-    optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
-    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
-        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+    if (code == 0) {
+        /* Copy all this junk into msg->im_data, keeping track of the lengths. */
+        cp = ioctlp->outDatap;
+        memcpy(cp, (char *)&scp->owner, sizeof(afs_uint32));
+        cp += sizeof(afs_uint32);
+        memcpy(cp, (char *)&scp->group, sizeof(afs_uint32));
+        cp += sizeof(afs_uint32);
 
-    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
-        cm_fid_t fid;
-        cm_SkipIoctlPath(ioctlp);
-        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
-                  optionsp->fid.vnode, optionsp->fid.unique);
-        code = cm_GetSCache(&fid, &scp, userp, &req);
-    } else {
-        code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+        /* return new size */
+        ioctlp->outDatap = cp;
     }
-    if (code) 
-        return code;
-
-    /* Copy all this junk into msg->im_data, keeping track of the lengths. */
-    cp = ioctlp->outDatap;
-    memcpy(cp, (char *)&scp->owner, sizeof(afs_uint32));
-    cp += sizeof(afs_uint32);
-    memcpy(cp, (char *)&scp->group, sizeof(afs_uint32));
-    cp += sizeof(afs_uint32);
-
-    /* return new size */
-    ioctlp->outDatap = cp;
-
-    cm_ReleaseSCache(scp);
-
-    return 0;
+    return code;
 }
 
-long cm_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
+
+/* 
+ * VIOCWHEREIS internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * scp is held but not locked.
+ */
+afs_int32 
+cm_IoctlWhereIs(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
 {
-    long code;
-    cm_scache_t *scp;
+    afs_int32 code;
     cm_cell_t *cellp;
     cm_volume_t *tvp;
     cm_serverRef_t **tsrpp, *current;
     cm_server_t *tsp;
-    unsigned long volume;
+    afs_uint32 volume;
     char *cp;
-    cm_req_t req;
-    cm_ioctlQueryOptions_t *optionsp;
-    afs_uint32 flags = 0;
-
-    cm_InitReq(&req);
-
-    optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
-    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
-        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
-
-    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
-        cm_fid_t fid;
-        cm_SkipIoctlPath(ioctlp);
-        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
-                  optionsp->fid.vnode, optionsp->fid.unique);
-        code = cm_GetSCache(&fid, &scp, userp, &req);
-    } else {
-        code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
-    }
-    if (code) 
-        return code;
 
     volume = scp->fid.volume;
 
     cellp = cm_FindCellByID(scp->fid.cell, 0);
 
-    cm_ReleaseSCache(scp);
-
     if (!cellp)
        return CM_ERROR_NOSUCHCELL;
 
@@ -1327,7 +844,7 @@ long cm_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
     } else 
 #endif
     {
-        code = cm_FindVolumeByID(cellp, volume, userp, &req, CM_GETVOL_FLAG_CREATE, &tvp);
+        code = cm_FindVolumeByID(cellp, volume, userp, reqp, CM_GETVOL_FLAG_CREATE, &tvp);
         if (code) 
             return code;
        
@@ -1354,72 +871,79 @@ long cm_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return 0;
 }       
 
-long cm_IoctlStatMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_AFS_STAT_MT_PT internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * scp is held but not locked.
+ */
+afs_int32 
+cm_IoctlStatMountPoint(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp, cm_req_t *reqp)
 {
-    long code;
-    cm_scache_t *dscp;
+    afs_int32 code;
     cm_scache_t *scp;
     char *cp;
-    cm_req_t req;
-
-    cm_InitReq(&req);
-
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
-    if (code) return code;
 
     cp = ioctlp->inDatap;
 
-    code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
-    cm_ReleaseSCache(dscp);
-    if (code) return code;
-        
+    code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
+    if (code) 
+        return code;
+
     lock_ObtainWrite(&scp->rw);
+    code = cm_SyncOp(scp, NULL, userp, reqp, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code == 0)
+        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    else
+        goto done;
 
     /* now check that this is a real mount point */
     if (scp->fileType != CM_SCACHETYPE_MOUNTPOINT) {
-        lock_ReleaseWrite(&scp->rw);
-        cm_ReleaseSCache(scp);
-        return CM_ERROR_INVAL;
+        code = CM_ERROR_INVAL;
+        goto done;
     }
 
-    code = cm_ReadMountPoint(scp, userp, &req);
+    code = cm_ReadMountPoint(scp, userp, reqp);
     if (code == 0) {
         cp = ioctlp->outDatap;
         StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), scp->mountPointStringp);
         cp += strlen(cp) + 1;
         ioctlp->outDatap = cp;
     }
+
+  done:
     lock_ReleaseWrite(&scp->rw);
     cm_ReleaseSCache(scp);
 
     return code;
 }       
 
-long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_AFS_DELETE_MT_PT internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * scp is held but not locked.
+ */
+afs_int32 
+cm_IoctlDeleteMountPoint(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp, cm_req_t *reqp)
 {
-    long code;
-    cm_scache_t *dscp;
+    afs_int32 code;
     cm_scache_t *scp;
     char *cp;
     char *originalName = NULL;
-    cm_req_t req;
     cm_dirOp_t dirop;
 
-    cm_InitReq(&req);
-
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
-    if (code) return code;
-
     cp = ioctlp->inDatap;
 
-    code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
+    code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
         
     /* if something went wrong, bail out now */
     if (code)
         goto done3;
         
     lock_ObtainWrite(&scp->rw);
-    code = cm_SyncOp(scp, NULL, userp, &req, 0,
+    code = cm_SyncOp(scp, NULL, userp, reqp, 0,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code)  
         goto done2;
@@ -1434,7 +958,7 @@ long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
     lock_ReleaseWrite(&scp->rw);
 
 #ifdef USE_BPLUS
-    code = cm_BeginDirOp(dscp, userp, &req, CM_DIRLOCK_READ, &dirop);
+    code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
     if (code == 0) {
         code = cm_BPlusDirLookupOriginalName(&dirop, cp, &originalName);
         /* The cm_Dir* functions can't be used to lookup the
@@ -1464,7 +988,7 @@ long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
 #endif
     {
         /* easier to do it this way */
-        code = cm_Unlink(dscp, originalName, cp, userp, &req);
+        code = cm_Unlink(dscp, originalName, cp, userp, reqp);
     }
     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
         smb_NotifyChange(FILE_ACTION_REMOVED,
@@ -1486,11 +1010,16 @@ long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
     cm_ReleaseSCache(scp);
 
   done3:
-    cm_ReleaseSCache(dscp);
     return code;
 }
 
-long cm_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOCCKSERV internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32 
+cm_IoctlCheckServers(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
     cm_cell_t *cellp;
     chservinfo_t csi;
@@ -1500,7 +1029,6 @@ long cm_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp)
     cm_server_t *tsp;
     int haveCell;
         
-    cm_SkipIoctlPath(ioctlp);  /* we don't care about the path */
     tp = ioctlp->inDatap;
     haveCell = 0;
 
@@ -1542,7 +1070,9 @@ long cm_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp)
     else cellp = (cm_cell_t *) 0;
     if (!cellp && (temp & 2)) {
         /* use local cell */
-        cellp = cm_FindCellByID(1, 0);
+        char wscell[CELL_MAXNAMELEN+1];
+        cm_GetRootCellName(wscell);
+        cellp = cm_GetCell(wscell, 0);
     }
     if (!(temp & 1)) { /* if not fast, call server checker routine */
         /* check down servers */
@@ -1554,7 +1084,8 @@ long cm_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp)
     cp = ioctlp->outDatap;
     lock_ObtainRead(&cm_serverLock);
     for (tsp = cm_allServersp; tsp; tsp=tsp->allNextp) {
-        if (cellp && tsp->cellp != cellp) continue;    /* cell spec'd and wrong */
+        if (cellp && tsp->cellp != cellp) 
+            continue;  /* cell spec'd and wrong */
         if ((tsp->flags & CM_SERVERFLAG_DOWN)
              && tsp->type == CM_SERVER_FILE) {
             memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
@@ -1567,24 +1098,32 @@ long cm_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return 0;
 }
 
-long cm_IoctlGag(struct smb_ioctl *ioctlp, struct cm_user *userp)
-{
-    /* we don't print anything superfluous, so we don't support the gag call */
-    return CM_ERROR_INVAL;
-}
-
-long cm_IoctlCheckVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOCCKBACK internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32 
+cm_IoctlCheckVolumes(cm_ioctl_t *ioctlp, cm_user_t *userp)
 {
     cm_RefreshVolumes();
     return 0;
 }       
 
-long cm_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOCSETCACHESIZE internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ *
+ * This function is no longer meaningful in the current day world
+ * of persistent caches.  The buf_SetNBuffers() function will
+ * inevitably fail.
+ */
+afs_int32 
+cm_IoctlSetCacheSize(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
+    afs_int32 code;
     afs_uint64 temp;
-    long code;
-
-    cm_SkipIoctlPath(ioctlp);
 
     memcpy(&temp, ioctlp->inDatap, sizeof(temp));
     if (temp == 0) 
@@ -1600,13 +1139,17 @@ long cm_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return code;
 }
 
-long cm_IoctlTraceControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_TRACECTL internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32 
+cm_IoctlTraceControl(cm_ioctl_t *ioctlp, cm_user_t *userp)
 {
-    long inValue;
-        
-    cm_SkipIoctlPath(ioctlp);
-        
-    memcpy(&inValue, ioctlp->inDatap, sizeof(long));
+    afs_uint32 inValue;
+
+    memcpy(&inValue, ioctlp->inDatap, sizeof(afs_uint32));
 
     /* print trace */
     if (inValue & 8) {
@@ -1635,12 +1178,18 @@ long cm_IoctlTraceControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
     /* and copy out tracing flag */
     inValue = afsd_logp->enabled;      /* use as a temp vbl */
-    memcpy(ioctlp->outDatap, &inValue, sizeof(long));
-    ioctlp->outDatap += sizeof(long);
+    memcpy(ioctlp->outDatap, &inValue, sizeof(afs_uint32));
+    ioctlp->outDatap += sizeof(afs_uint32);
     return 0;
 }       
 
-long cm_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOCGETCACHEPARMS internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32 
+cm_IoctlGetCacheParms(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
     cm_cacheParms_t parms;
 
@@ -1660,7 +1209,13 @@ long cm_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return 0;
 }
 
-long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOCGETCELL internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32 
+cm_IoctlGetCell(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
     long whichCell;
     long magic = 0;
@@ -1672,21 +1227,20 @@ long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
     char *tp;
     char *basep;
 
-    cm_SkipIoctlPath(ioctlp);
-
     tp = ioctlp->inDatap;
 
     memcpy((char *)&whichCell, tp, sizeof(long));
     tp += sizeof(long);
 
     /* see if more than one long passed in, ignoring the null pathname (the -1) */
-    if (ioctlp->inCopied-1 > sizeof(long)) {
-        memcpy((char *)&magic, tp, sizeof(long));
+    if (ioctlp->inCopied-1 > sizeof(afs_uint32)) {
+        memcpy((char *)&magic, tp, sizeof(afs_uint32));
     }
 
     lock_ObtainRead(&cm_cellLock);
     for (tcellp = cm_data.allCellsp; tcellp; tcellp = tcellp->allNextp) {
-        if (whichCell == 0) break;
+        if (whichCell == 0)
+            break;
         whichCell--;
     }
     lock_ReleaseRead(&cm_cellLock);
@@ -1702,14 +1256,12 @@ long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
         memset(cp, 0, max * sizeof(long));
         basep = cp;
         lock_ObtainRead(&cm_serverLock);       /* for going down server list */
-        /* jaltman - do the reference counts to serverRefp contents need to be increased? */
-        serverRefp = tcellp->vlServersp;
-        for (i=0; i<max; i++) {
-            if (!serverRefp) break;
+        for (i=0, serverRefp = tcellp->vlServersp; 
+             serverRefp && i<max; 
+             i++, serverRefp = serverRefp->next) {
             serverp = serverRefp->server;
             memcpy(cp, &serverp->addr.sin_addr.s_addr, sizeof(long));
             cp += sizeof(long);
-            serverRefp = serverRefp->next;
         }
         lock_ReleaseRead(&cm_serverLock);
         cp = basep + max * sizeof(afs_int32);
@@ -1724,11 +1276,16 @@ long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
         return CM_ERROR_NOMORETOKENS;  /* mapped to EDOM */
 }
 
-long cm_IoctlNewCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
+
+/* 
+ * VIOCNEWCELL internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32 
+cm_IoctlNewCell(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
-    /* NT cache manager will read cell information from CellServDB each time
-     * cell is accessed. So, this call is necessary only if list of server for a cell 
-     * changes (or IP addresses of cell servers changes).
+    /* 
      * All that needs to be done is to refresh server information for all cells that 
      * are already loaded.
   
@@ -1738,13 +1295,11 @@ long cm_IoctlNewCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
     cm_cell_t *cp;
     cm_cell_rock_t rock;
 
-  
-    cm_SkipIoctlPath(ioctlp);
     lock_ObtainWrite(&cm_cellLock);
   
     for (cp = cm_data.allCellsp; cp; cp=cp->allNextp) 
     {
-        long code;
+        afs_int32 code;
        lock_ObtainMutex(&cp->mx);
         /* delete all previous server lists - cm_FreeServerList will ask for write on cm_ServerLock*/
         cm_FreeServerList(&cp->vlServersp, CM_FREESERVERLIST_DELETE);
@@ -1782,37 +1337,47 @@ long cm_IoctlNewCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return 0;       
 }
 
-long cm_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp)
-{
-       long code = 0;
-
-       if (cm_freelanceEnabled) {
-            if (cm_GetRootCellName(ioctlp->outDatap))
-                StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), "Freelance.Local.Root");
-            ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
-       } else if (cm_data.rootCellp) {
-           /* return the default cellname to the caller */
-           StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), cm_data.rootCellp->name);
-           ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
-       } else {
-           /* if we don't know our default cell, return failure */
-            code = CM_ERROR_NOSUCHCELL;
-    }
+/* 
+ * VIOC_GET_WS_CELL internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32 
+cm_IoctlGetWsCell(cm_ioctl_t *ioctlp, cm_user_t *userp)
+{
+    afs_int32 code = 0;
+
+    if (cm_freelanceEnabled) {
+        if (cm_GetRootCellName(ioctlp->outDatap))
+            StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), "Freelance.Local.Root");
+        ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
+    } else if (cm_data.rootCellp) {
+        /* return the default cellname to the caller */
+        StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), cm_data.rootCellp->name);
+        ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
+    } else {
+        /* if we don't know our default cell, return failure */
+        code = CM_ERROR_NOSUCHCELL;
+    }   
 
     return code;
 }
 
-long cm_IoctlSysName(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_AFS_SYSNAME internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32 
+cm_IoctlSysName(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
-    long setSysName, foundname = 0;
+    afs_uint32 setSysName, foundname = 0;
     char *cp, *cp2, inname[MAXSYSNAME], outname[MAXSYSNAME];
     int t, count, num = 0;
     char **sysnamelist[MAXSYSNAME];
         
-    cm_SkipIoctlPath(ioctlp);
-
-    memcpy(&setSysName, ioctlp->inDatap, sizeof(long));
-    ioctlp->inDatap += sizeof(long);
+    memcpy(&setSysName, ioctlp->inDatap, sizeof(afs_uint32));
+    ioctlp->inDatap += sizeof(afs_uint32);
         
     if (setSysName) {
         /* check my args */
@@ -1895,13 +1460,17 @@ long cm_IoctlSysName(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return 0;
 }
 
-long cm_IoctlGetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_GETCELLSTATUS internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32 
+cm_IoctlGetCellStatus(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
-    long temp;
+    afs_uint32 temp;
     cm_cell_t *cellp;
 
-    cm_SkipIoctlPath(ioctlp);
-
     cellp = cm_GetCell(ioctlp->inDatap, 0);
     if (!cellp) 
         return CM_ERROR_NOSUCHCELL;
@@ -1913,24 +1482,28 @@ long cm_IoctlGetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
     lock_ReleaseMutex(&cellp->mx);
         
     /* now copy out parm */
-    memcpy(ioctlp->outDatap, &temp, sizeof(long));
-    ioctlp->outDatap += sizeof(long);
+    memcpy(ioctlp->outDatap, &temp, sizeof(afs_uint32));
+    ioctlp->outDatap += sizeof(afs_uint32);
 
     return 0;
 }
 
-long cm_IoctlSetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_SETCELLSTATUS internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32 
+cm_IoctlSetCellStatus(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
-    long temp;
+    afs_uint32 temp;
     cm_cell_t *cellp;
 
-    cm_SkipIoctlPath(ioctlp);
-
-    cellp = cm_GetCell(ioctlp->inDatap + 2*sizeof(long), 0);
+    cellp = cm_GetCell(ioctlp->inDatap + 2*sizeof(afs_uint32), 0);
     if (!cellp) 
         return CM_ERROR_NOSUCHCELL;
 
-    memcpy((char *)&temp, ioctlp->inDatap, sizeof(long));
+    memcpy((char *)&temp, ioctlp->inDatap, sizeof(afs_uint32));
 
     lock_ObtainMutex(&cellp->mx);
     if (temp & CM_SETCELLFLAG_SUID)
@@ -1942,16 +1515,20 @@ long cm_IoctlSetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return 0;
 }
 
-long cm_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_SETSPREFS internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32 
+cm_IoctlSetSPrefs(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
-    cm_SSetPref_t        *spin; /* input */
+    cm_SSetPref_t     *spin;    /* input */
     cm_SPref_t        *srvin;   /* one input component */
     cm_server_t       *tsp;
-    int                  i, vlonly, noServers, type;
-    struct sockaddr_in tmp;
-    unsigned short       rank;
-
-    cm_SkipIoctlPath(ioctlp);       /* we don't care about the path */
+    int               i, vlonly, noServers, type;
+    struct sockaddr_in tmp;
+    unsigned short     rank;
 
     spin          = (cm_SSetPref_t *)ioctlp->inDatap;
     noServers  = spin->num_servers;
@@ -2000,7 +1577,13 @@ long cm_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return 0;
 }
 
-long cm_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_GETSPREFS internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32
+cm_IoctlGetSPrefs(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
     cm_SPrefRequest_t *spin; /* input */
     cm_SPrefInfo_t    *spout;   /* output */
@@ -2008,8 +1591,6 @@ long cm_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
     cm_server_t       *tsp;
     int                  i, vlonly, noServers;
 
-    cm_SkipIoctlPath(ioctlp);       /* we don't care about the path */
-
     spin      = (cm_SPrefRequest_t *)ioctlp->inDatap;
     spout     = (cm_SPrefInfo_t *) ioctlp->outDatap;
     srvout    = spout->servers;
@@ -2046,40 +1627,31 @@ long cm_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return 0;
 }
 
-long cm_IoctlStoreBehind(struct smb_ioctl *ioctlp, struct cm_user *userp)
-{
-    /* we ignore default asynchrony since we only have one way
-     * of doing this today.
-     */
-    return 0;
-}       
 
-long cm_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_AFS_CREATE_MT_PT internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * dscp is held but not locked.
+ */
+afs_int32
+cm_IoctlCreateMountPoint(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp, cm_req_t *reqp, char *leaf)
 {
-    char leaf[LEAF_SIZE];
-    long code;
-    cm_scache_t *dscp;
+    afs_int32 code;
     cm_attr_t tattr;
     char *cp;
-    cm_req_t req;
     char mpInfo[256];
     char fullCell[256];
     char volume[256];
     char cell[256];
     int ttl;
 
-    cm_InitReq(&req);
-        
-    code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
-    if (code) 
-        return code;
-
     /* Translate chars for the mount point name */
-    if (!(ioctlp->flags & SMB_IOCTLFLAG_USEUTF8)) {
-    TranslateExtendedChars(leaf);
+    if (!(ioctlp->flags & CM_IOCTLFLAG_USEUTF8)) {
+        TranslateExtendedChars(leaf);
     }
 
-    /* 
+   /* 
      * The fs command allows the user to specify partial cell names on NT.  These must
      * be expanded to the full cell name for mount points so that the mount points will
      * work on UNIX clients.
@@ -2100,7 +1672,6 @@ long cm_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
             code = cm_SearchCellByDNS(cell, fullCell, &ttl, 0, 0);
 #endif
         if (code) {
-            cm_ReleaseSCache(dscp);
             return CM_ERROR_NOSUCHCELL;
         }
        
@@ -2127,7 +1698,7 @@ long cm_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
         tattr.unixModeBits = 0644;
         tattr.clientModTime = time(NULL);
 
-        code = cm_SymLink(dscp, leaf, mpInfo, 0, &tattr, userp, &req);
+        code = cm_SymLink(dscp, leaf, mpInfo, 0, &tattr, userp, reqp);
     }
     
     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
@@ -2135,32 +1706,30 @@ long cm_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
                          FILE_NOTIFY_CHANGE_DIR_NAME,
                          dscp, leaf, NULL, TRUE);
 
-    cm_ReleaseSCache(dscp);
     return code;
 }
 
-long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_SYMLINK internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * dscp is held but not locked.
+ */
+afs_int32 
+cm_IoctlSymlink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp, cm_req_t *reqp, char *leaf)
 {
-    char leaf[LEAF_SIZE];
-    long code;
-    cm_scache_t *dscp;
+    afs_int32 code;
     cm_attr_t tattr;
     char *cp;
-    cm_req_t req;
     char *symlp;
     int free_syml = FALSE;
 
-    cm_InitReq(&req);
-
-    code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
-    if (code) return code;
-
-    if (!(ioctlp->flags & SMB_IOCTLFLAG_USEUTF8)) {
-    /* Translate chars for the link name */
-    TranslateExtendedChars(leaf);
+    if (!(ioctlp->flags & CM_IOCTLFLAG_USEUTF8)) {
+        /* Translate chars for the link name */
+        TranslateExtendedChars(leaf);
 
-    /* Translate chars for the linked to name */
-    TranslateExtendedChars(ioctlp->inDatap);
+        /* Translate chars for the linked to name */
+        TranslateExtendedChars(ioctlp->inDatap);
     }
 
     symlp = ioctlp->inDatap;           /* contents of link */
@@ -2210,7 +1779,7 @@ long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
         tattr.mask = CM_ATTRMASK_UNIXMODEBITS;
         tattr.unixModeBits = 0755;
 
-        code = cm_SymLink(dscp, leaf, cp, 0, &tattr, userp, &req);
+        code = cm_SymLink(dscp, leaf, cp, 0, &tattr, userp, reqp);
     }
 
     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
@@ -2219,8 +1788,6 @@ long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
                           | FILE_NOTIFY_CHANGE_DIR_NAME,
                           dscp, leaf, NULL, TRUE);
 
-    cm_ReleaseSCache(dscp);
-
     if (free_syml)
         free(symlp);
 
@@ -2228,26 +1795,30 @@ long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
 }
 
 
-long cm_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_LISTSYMLINK internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * dscp is held but not locked.
+ */
+afs_int32 
+cm_IoctlListlink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp, cm_req_t *reqp)
 {
-    long code;
-    cm_scache_t *dscp;
+    afs_int32 code;
     cm_scache_t *scp;
     char *cp;
     cm_space_t *spacep;
     cm_scache_t *newRootScp;
-    cm_req_t req;
-
-    cm_InitReq(&req);
-
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
-    if (code) return code;
 
+    if (!(ioctlp->flags & CM_IOCTLFLAG_USEUTF8)) {
+        /* Translate chars for the link name */
+        TranslateExtendedChars(ioctlp->inDatap);
+    }
     cp = ioctlp->inDatap;
 
-    code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
-    cm_ReleaseSCache(dscp);
-    if (code) return code;
+    code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
+    if (code) 
+        return code;
 
     /* Check that it's a real symlink */
     if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
@@ -2257,7 +1828,7 @@ long cm_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
         return CM_ERROR_INVAL;
     }
 
-    code = cm_AssembleLink(scp, "", &newRootScp, &spacep, userp, &req);
+    code = cm_AssembleLink(scp, "", &newRootScp, &spacep, userp, reqp);
     cm_ReleaseSCache(scp);
     if (code == 0) {
         cp = ioctlp->outDatap;
@@ -2288,25 +1859,29 @@ long cm_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return code;
 }
 
-long cm_IoctlIslink(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_ISSYMLINK internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * dscp is held but not locked.
+ */
+afs_int32 
+cm_IoctlIslink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp, cm_req_t *reqp)
 {/*CHECK FOR VALID SYMLINK*/
-    long code;
-    cm_scache_t *dscp;
+    afs_int32 code;
     cm_scache_t *scp;
     char *cp;
-    cm_req_t req;
-
-    cm_InitReq(&req);
-
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
-    if (code) return code;
 
+    if (!(ioctlp->flags & CM_IOCTLFLAG_USEUTF8)) {
+        /* Translate chars for the link name */
+        TranslateExtendedChars(ioctlp->inDatap);
+    }
     cp = ioctlp->inDatap;
     osi_LogEvent("cm_IoctlListlink",NULL," name[%s]",cp);
 
-    code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
-    cm_ReleaseSCache(dscp);
-    if (code) return code;
+    code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
+    if (code)
+        return code;
 
     /* Check that it's a real symlink */
     if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
@@ -2317,31 +1892,35 @@ long cm_IoctlIslink(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return code;
 }
 
-long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_DELSYMLINK internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * dscp is held but not locked.
+ */
+afs_int32
+cm_IoctlDeletelink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp, cm_req_t *reqp)
 {
-    long code;
-    cm_scache_t *dscp;
+    afs_int32 code;
     cm_scache_t *scp;
     char *cp;
     char * originalName = NULL;
-    cm_req_t req;
     cm_dirOp_t dirop;
 
-    cm_InitReq(&req);
-
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
-    if (code) return code;
-
+    if (!(ioctlp->flags & CM_IOCTLFLAG_USEUTF8)) {
+        /* Translate chars for the link name */
+        TranslateExtendedChars(ioctlp->inDatap);
+    }
     cp = ioctlp->inDatap;
 
-    code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
+    code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
         
     /* if something went wrong, bail out now */
     if (code)
         goto done3;
         
     lock_ObtainWrite(&scp->rw);
-    code = cm_SyncOp(scp, NULL, userp, &req, 0,
+    code = cm_SyncOp(scp, NULL, userp, reqp, 0,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code)
         goto done2;
@@ -2358,7 +1937,7 @@ long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
     lock_ReleaseWrite(&scp->rw);
         
 #ifdef USE_BPLUS
-    code = cm_BeginDirOp(dscp, userp, &req, CM_DIRLOCK_READ, &dirop);
+    code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
     if (code == 0) {
         code = cm_BPlusDirLookupOriginalName(&dirop, cp, &originalName);
         /* cm_Dir*() functions can't be used to lookup the original
@@ -2389,7 +1968,7 @@ long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
 #endif
     {
         /* easier to do it this way */
-        code = cm_Unlink(dscp, originalName, cp, userp, &req);
+        code = cm_Unlink(dscp, originalName, cp, userp, reqp);
     }
     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
         smb_NotifyChange(FILE_ACTION_REMOVED,
@@ -2412,12 +1991,16 @@ long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
     cm_ReleaseSCache(scp);
 
   done3:
-    cm_ReleaseSCache(dscp);
     return code;
 }
 
 #ifdef QUERY_AFSID
-long cm_UsernameToId(char *uname, cm_ucell_t * ucellp, afs_uint32* uid)
+/* Utility function.  Not currently used.  
+ * This function performs a PTS lookup which has traditionally
+ * not been performed by the cache manager.
+ */
+afs_int32 
+cm_UsernameToId(char *uname, cm_ucell_t * ucellp, afs_uint32* uid)
 {
     afs_int32 code;
     namelist lnames;
@@ -2493,7 +2076,13 @@ long cm_UsernameToId(char *uname, cm_ucell_t * ucellp, afs_uint32* uid)
 }
 #endif /* QUERY_AFSID */
 
-long cm_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
+#if 0
+/* This has been copied to smb_IoctlSetToken in its entirety.
+ * An equivalent version will need to be produced for the 
+ * redirector and some extensive refactoring might be required.
+ */
+afs_int32
+cm_IoctlSetToken(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
     char *saveDataPtr;
     char *tp;
@@ -2614,7 +2203,7 @@ long cm_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
     lock_ReleaseMutex(&userp->mx);
 
     if (flags & PIOCTL_LOGON) {
-        ioctlp->flags |= SMB_IOCTLFLAG_LOGON;
+        ioctlp->flags |= CM_IOCTLFLAG_LOGON;
     }
 
     cm_ResetACLCache(userp);
@@ -2624,8 +2213,15 @@ long cm_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
     return 0;
 }
+#endif
 
-long cm_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_GETTOK internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32
+cm_IoctlGetTokenIter(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
     char *tp, *cp;
     int iterator;
@@ -2633,8 +2229,6 @@ long cm_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp)
     cm_ucell_t *ucellp;
     struct ClearToken ct;
 
-    cm_SkipIoctlPath(ioctlp);
-
     tp = ioctlp->inDatap;
     cp = ioctlp->outDatap;
 
@@ -2675,12 +2269,13 @@ long cm_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
     /* clear token */
     ct.AuthHandle = ucellp->kvno;
+
     /*
-     * Don't give out a real session key here
+     * This field is supposed to hold the session key
+     * but we don't want to make it easier for someone 
+     * to attack the cache.  The user gave us the session
+     * key in the first place.
      */
-    /*
-    memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
-    */
     memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
     ct.ViceId = 37;                    /* XXX */
     ct.BeginTimestamp = 0;             /* XXX */
@@ -2708,7 +2303,13 @@ long cm_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return 0;
 }
 
-long cm_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_NEWGETTOK internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32
+cm_IoctlGetToken(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
     char *cp;
     int temp;
@@ -2717,7 +2318,6 @@ long cm_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
     struct ClearToken ct;
     char *tp;
     afs_uuid_t uuid;
-    cm_SkipIoctlPath(ioctlp);
 
     tp = ioctlp->inDatap;
 
@@ -2755,12 +2355,8 @@ long cm_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
     /* clear token */
     ct.AuthHandle = ucellp->kvno;
-    /*
-     * Don't give out a real session key here
-     */
-    /*
-    memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
-    */
+
+    /* do not give out the session key */
     memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
     ct.ViceId = 37;                    /* XXX */
     ct.BeginTimestamp = 0;             /* XXX */
@@ -2790,14 +2386,18 @@ long cm_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return 0;
 }
 
-long cm_IoctlDelToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOCDELTOK internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32
+cm_IoctlDelToken(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
     char *cp;
     cm_cell_t *cellp;
     cm_ucell_t *ucellp;
 
-    cm_SkipIoctlPath(ioctlp);
-
     cp = ioctlp->outDatap;
 
     /* cell name is right here */
@@ -2834,7 +2434,13 @@ long cm_IoctlDelToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return 0;
 }
 
-long cm_IoctlDelAllToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOCDELALLTOK internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32
+cm_IoctlDelAllToken(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
     cm_ucell_t *ucellp;
 
@@ -2863,7 +2469,13 @@ long cm_IoctlDelAllToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return 0;
 }
 
-long cm_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp)
+/* 
+ * VIOC_MAKESUBMOUNT internals.  (This function should be deprecated)
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32
+cm_IoctlMakeSubmount(cm_ioctl_t *ioctlp, cm_user_t *userp)
 {
     char afspath[MAX_PATH];
     char *submountreqp;
@@ -2874,8 +2486,6 @@ long cm_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp)
     DWORD dwIndex;
     DWORD dwSubmounts;
 
-    cm_SkipIoctlPath(ioctlp);
-
     /* Serialize this one, to prevent simultaneous mods
      * to afsdsbmt.ini
      */
@@ -3038,7 +2648,13 @@ long cm_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp)
     return 0;
 }
 
-long cm_IoctlGetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
+/* 
+ * VIOC_GETRXKCRYPT internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32
+cm_IoctlGetRxkcrypt(cm_ioctl_t *ioctlp, cm_user_t *userp)
 {
     memcpy(ioctlp->outDatap, &cryptall, sizeof(cryptall));
     ioctlp->outDatap += sizeof(cryptall);
@@ -3046,12 +2662,16 @@ long cm_IoctlGetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
     return 0;
 }
 
-long cm_IoctlSetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
+/* 
+ * VIOC_SETRXKCRYPT internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32
+cm_IoctlSetRxkcrypt(cm_ioctl_t *ioctlp, cm_user_t *userp)
 {
     afs_int32 c = cryptall;
 
-    cm_SkipIoctlPath(ioctlp);
-
     memcpy(&cryptall, ioctlp->inDatap, sizeof(cryptall));
 
     if (c != cryptall) {
@@ -3063,13 +2683,17 @@ long cm_IoctlSetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
     return 0;
 }
 
-long cm_IoctlRxStatProcess(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_RXSTAT_PROC internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32
+cm_IoctlRxStatProcess(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
     afs_int32 flags;
     int code = 0;
 
-    cm_SkipIoctlPath(ioctlp);
-
     memcpy((char *)&flags, ioctlp->inDatap, sizeof(afs_int32));
     if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
         return -1;
@@ -3086,13 +2710,17 @@ long cm_IoctlRxStatProcess(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return 0;
 }
 
-long cm_IoctlRxStatPeer(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_RXSTAT_PEER internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32
+cm_IoctlRxStatPeer(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
     afs_int32 flags;
     int code = 0;
 
-    cm_SkipIoctlPath(ioctlp);
-
     memcpy((char *)&flags, ioctlp->inDatap, sizeof(afs_int32));
     if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
        return -1;
@@ -3109,27 +2737,19 @@ long cm_IoctlRxStatPeer(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return 0;
 }
 
-long cm_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp)
-{
-  smb_user_t *uidp = ioctlp->uidp;
-
-  if (uidp && uidp->unp) {
-    memcpy(ioctlp->outDatap, uidp->unp->name, strlen(uidp->unp->name));
-    ioctlp->outDatap += strlen(uidp->unp->name);
-  }
-
-  return 0;
-}
-
-long cm_IoctlUnicodeControl(struct smb_ioctl *ioctlp, struct cm_user * userp)
+/* 
+ * VIOC_UNICODECTL internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32
+cm_IoctlUnicodeControl(struct cm_ioctl *ioctlp, struct cm_user * userp)
 {
-    long result = 0;
+    afs_int32 result = 0;
 #ifdef SMB_UNICODE
-    long cmd;
-
-    cm_SkipIoctlPath(ioctlp);
+    afs_uint32 cmd;
 
-    memcpy(&cmd, ioctlp->inDatap, sizeof(long));
+    memcpy(&cmd, ioctlp->inDatap, sizeof(afs_uint32));
 
     if (cmd & 2) {
         /* Setting the Unicode flag */
@@ -3151,14 +2771,18 @@ long cm_IoctlUnicodeControl(struct smb_ioctl *ioctlp, struct cm_user * userp)
     return 0;
 }
 
-long cm_IoctlUUIDControl(struct smb_ioctl * ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_UUIDCTL internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32
+cm_IoctlUUIDControl(struct cm_ioctl * ioctlp, struct cm_user *userp)
 {
-    long cmd;
+    afs_uint32 cmd;
     afsUUID uuid;
 
-    cm_SkipIoctlPath(ioctlp);
-
-    memcpy(&cmd, ioctlp->inDatap, sizeof(long));
+    memcpy(&cmd, ioctlp->inDatap, sizeof(afs_uint32));
 
     if (cmd) {             /* generate a new UUID */
         UuidCreate((UUID *) &uuid);
@@ -3182,9 +2806,16 @@ extern int cm_DumpSCache(FILE *outputFile, char *cookie, int lock);
 extern int cm_DumpBufHashTable(FILE *outputFile, char *cookie, int lock);
 extern int smb_DumpVCP(FILE *outputFile, char *cookie, int lock);
 
-long cm_IoctlMemoryDump(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_TRACEMEMDUMP internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * dscp is held but not locked.
+ */
+afs_int32
+cm_IoctlMemoryDump(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
-    long inValue = 0;
+    afs_int32 inValue = 0;
     HANDLE hLogFile;
     char logfileName[MAX_PATH+1];
     char *cookie;
@@ -3194,8 +2825,7 @@ long cm_IoctlMemoryDump(struct smb_ioctl *ioctlp, struct cm_user *userp)
     static _CrtMemState memstate;
 #endif
   
-    cm_SkipIoctlPath(ioctlp);
-    memcpy(&inValue, ioctlp->inDatap, sizeof(long));
+    memcpy(&inValue, ioctlp->inDatap, sizeof(afs_int32));
   
     dwSize = GetEnvironmentVariable("TEMP", logfileName, sizeof(logfileName));
     if ( dwSize == 0 || dwSize > sizeof(logfileName) )
@@ -3210,8 +2840,8 @@ long cm_IoctlMemoryDump(struct smb_ioctl *ioctlp, struct cm_user *userp)
     {
       /* error */
       inValue = -1;
-      memcpy(ioctlp->outDatap, &inValue, sizeof(long));
-      ioctlp->outDatap += sizeof(long);
+      memcpy(ioctlp->outDatap, &inValue, sizeof(afs_int32));
+      ioctlp->outDatap += sizeof(afs_int32);
       
       return 0;               
     }
@@ -3252,11 +2882,11 @@ long cm_IoctlMemoryDump(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return 0;
 }
 
-
-static long 
+/* Utility functon.  Not currently used. */
+static afs_int32
 cm_CheckServersStatus(cm_serverRef_t *serversp)
 {
-    long code = 0;
+    afs_int32 code = 0;
     cm_serverRef_t *tsrp;
     cm_server_t *tsp;
     int someBusy = 0, someOffline = 0, allOffline = 1, allBusy = 1, allDown = 1;
@@ -3304,41 +2934,24 @@ cm_CheckServersStatus(cm_serverRef_t *serversp)
     return code;
 }
 
-
-long cm_IoctlPathAvailability(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_PATH_AVAILABILITY internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ * scp is held but not locked.
+ */
+afs_int32
+cm_IoctlPathAvailability(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
 {
-    long code;
-    cm_scache_t *scp;
+    afs_int32 code;
     cm_cell_t *cellp;
     cm_volume_t *tvp;
     cm_vol_state_t *statep;
     afs_uint32 volume;
-    cm_req_t req;
-    cm_ioctlQueryOptions_t *optionsp;
-    afs_uint32 flags = 0;
-
-    cm_InitReq(&req);
-
-    optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
-    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
-        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
-
-    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
-        cm_fid_t fid;
-        cm_SkipIoctlPath(ioctlp);
-        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
-                  optionsp->fid.vnode, optionsp->fid.unique);
-        code = cm_GetSCache(&fid, &scp, userp, &req);
-    } else {
-        code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
-    }
-    if (code) 
-        return code;
         
 #ifdef AFS_FREELANCE_CLIENT
     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
        code = 0;
-       cm_ReleaseSCache(scp);
     } else
 #endif
     {
@@ -3346,12 +2959,10 @@ long cm_IoctlPathAvailability(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
         cellp = cm_FindCellByID(scp->fid.cell, 0);
 
-        cm_ReleaseSCache(scp);
-
         if (!cellp)
             return CM_ERROR_NOSUCHCELL;
 
-        code = cm_FindVolumeByID(cellp, volume, userp, &req, CM_GETVOL_FLAG_CREATE, &tvp);
+        code = cm_FindVolumeByID(cellp, volume, userp, reqp, CM_GETVOL_FLAG_CREATE, &tvp);
         if (code) 
             return code;
        
@@ -3376,20 +2987,24 @@ long cm_IoctlPathAvailability(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return code;
 }       
 
-
-long cm_IoctlVolStatTest(struct smb_ioctl *ioctlp, struct cm_user *userp)
+/* 
+ * VIOC_VOLSTAT_TEST internals.
+ * 
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32
+cm_IoctlVolStatTest(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
-    long code;
+    afs_int32 code;
     cm_cell_t *cellp = NULL;
     cm_volume_t *volp;
     cm_vol_state_t *statep;
     struct VolStatTest * testp;
-    cm_req_t req;
     afs_uint32 n;
+    cm_req_t req;
 
     cm_InitReq(&req);
 
-    cm_SkipIoctlPath(ioctlp);  /* we don't care about the path */
     testp = (struct VolStatTest *)ioctlp->inDatap;
 
 #ifdef AFS_FREELANCE_CLIENT
index 934959a..bb188f2 100644 (file)
@@ -11,7 +11,6 @@
 #define __CM_IOCTL_H_ENV__ 1
 
 #ifndef __CM_IOCTL_INTERFACES_ONLY__
-#include "smb.h"
 #include "cm_user.h"
 #else
 typedef struct cm_fid {
@@ -52,6 +51,28 @@ typedef struct cm_cacheParms {
         afs_uint64 parms[CM_IOCTLCACHEPARMS];
 } cm_cacheParms_t;
 
+typedef struct cm_ioctl {
+    /* input side */
+    char *inDatap;                     /* ioctl func's current position
+                                        * in input parameter block */
+    char *inAllocp;                    /* allocated input parameter block */
+    afs_uint32 inCopied;               /* # of input bytes copied in so far
+                                        * by write calls */
+    /* output side */
+    char *outDatap;                    /* output results assembled so far */
+    char *outAllocp;                   /* output results assembled so far */
+    afs_uint32 outCopied;              /* # of output bytes copied back so far
+       
+    /* flags */
+    afs_uint32 flags;
+} cm_ioctl_t;
+
+/* flags for smb_ioctl_t */
+#define CM_IOCTLFLAG_DATAIN    1       /* reading data from client to server */
+#define CM_IOCTLFLAG_LOGON     2       /* got tokens from integrated logon */
+#define CM_IOCTLFLAG_USEUTF8    4       /* this request is using UTF-8 strings */
+
+
 /* 
  * The cm_IoctlQueryOptions structure is designed to be extendible.
  * None of the fields are required but when specified 
@@ -106,6 +127,9 @@ extern char *         cm_sysNameList[MAXNUMSYSNAMES];
    strings. */
 #define UTF8_PREFIX "\33%G"
 
+extern const char utf8_prefix[];
+extern const int  utf8_prefix_size;
+
 /* flags for rxstats pioctl */
 
 #define AFSCALL_RXSTATS_MASK    0x7     /* Valid flag bits */
@@ -115,121 +139,129 @@ extern char *         cm_sysNameList[MAXNUMSYSNAMES];
 
 #ifndef __CM_IOCTL_INTERFACES_ONLY__
 
-void cm_InitIoctl(void);
+extern void cm_InitIoctl(void);
+
+extern void cm_ResetACLCache(cm_user_t *userp);
+
+extern cm_ioctlQueryOptions_t * cm_IoctlGetQueryOptions(struct cm_ioctl *ioctlp, struct cm_user *userp);
+
+extern void cm_IoctlSkipQueryOptions(struct cm_ioctl *ioctlp, struct cm_user *userp);
+
+extern void cm_NormalizeAfsPath(char *outpathp, long outlen, char *inpathp);
 
-void cm_ResetACLCache(cm_user_t *userp);
+extern void cm_SkipIoctlPath(cm_ioctl_t *ioctlp);
 
-extern long cm_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlGetACL(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
 
-extern long cm_IoctlGetFileCellName(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlGetFileCellName(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
 
-extern long cm_IoctlSetACL(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlSetACL(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
 
-extern long cm_IoctlFlushAllVolumes(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlFlushAllVolumes(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlFlushVolume(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlFlushVolume(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
 
-extern long cm_IoctlFlushFile(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlFlushFile(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
 
-extern long cm_IoctlSetVolumeStatus(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlSetVolumeStatus(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
 
-extern long cm_IoctlGetVolumeStatus(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlGetVolumeStatus(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
 
-extern long cm_IoctlGetFid(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlGetFid(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
 
-extern long cm_IoctlGetOwner(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlGetOwner(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
 
-extern long cm_IoctlWhereIs(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlWhereIs(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
 
-extern long cm_IoctlStatMountPoint(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlStatMountPoint(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
 
-extern long cm_IoctlDeleteMountPoint(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlDeleteMountPoint(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
 
-extern long cm_IoctlCheckServers(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlCheckServers(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlGag(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlGag(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlCheckVolumes(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlCheckVolumes(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlSetCacheSize(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlSetCacheSize(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlGetCacheParms(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlGetCacheParms(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlGetCell(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlGetCell(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlNewCell(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlNewCell(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlGetWsCell(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlSysName(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlSysName(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlGetCellStatus(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlGetCellStatus(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlSetCellStatus(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlSetCellStatus(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlSetSPrefs(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlSetSPrefs(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlGetSPrefs(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlGetSPrefs(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlStoreBehind(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlStoreBehind(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlCreateMountPoint(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlCreateMountPoint(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *dscp, cm_req_t *reqp, char *leaf);
 
-extern long cm_CleanFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
+extern afs_int32 cm_CleanFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
 
-extern long cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
+extern afs_int32 cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
 
-extern long cm_FlushVolume(cm_user_t *, cm_req_t *reqp, afs_uint32 cell, afs_uint32 volume);
+extern afs_int32 cm_FlushVolume(cm_user_t *, cm_req_t *reqp, afs_uint32 cell, afs_uint32 volume);
 
-extern long cm_FlushParent(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
+extern afs_int32 cm_FlushParent(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
 
-extern long cm_IoctlTraceControl(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlTraceControl(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlSetToken(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlSetToken(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlGetTokenIter(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlGetTokenIter(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlGetToken(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlGetToken(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlDelToken(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlDelToken(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlDelAllToken(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlDelAllToken(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlSymlink(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlSymlink(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *dscp, cm_req_t *reqp, char *leaf);
 
-extern long cm_IoctlIslink(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlIslink(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
 
-extern long cm_IoctlListlink(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlListlink(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
 
-extern long cm_IoctlDeletelink(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlDeletelink(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *dscp, cm_req_t *reqp);
 
-extern long cm_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlMakeSubmount(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlGetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlGetRxkcrypt(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlSetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlSetRxkcrypt(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlShutdown(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlShutdown(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlFreemountAddCell(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlFreemountAddCell(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlFreemountRemoveCell(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlFreemountRemoveCell(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlMemoryDump(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlMemoryDump(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlRxStatProcess(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlRxStatProcess(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlRxStatPeer(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlRxStatPeer(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long cm_IoctlUUIDControl(struct smb_ioctl * ioctlp, struct cm_user *userp);
+extern afs_int32 cm_IoctlUUIDControl(struct cm_ioctl * ioctlp, struct cm_user *userp);
 
-extern long cm_IoctlPathAvailability(struct smb_ioctl * ioctlp, struct cm_user *userp);
+extern afs_int32 cm_IoctlPathAvailability(struct cm_ioctl * ioctlp, struct cm_user *userp, struct cm_scache *scp, struct cm_req *reqp);
 
-extern long cm_IoctlGetFileType(smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 cm_IoctlGetFileType(cm_ioctl_t *ioctlp, cm_user_t *userp, struct cm_scache *scp, struct cm_req *reqp);
 
-extern long cm_IoctlVolStatTest(struct smb_ioctl *ioctlp, struct cm_user *userp);
+extern afs_int32 cm_IoctlVolStatTest(struct cm_ioctl *ioctlp, struct cm_user *userp);
 
-extern long cm_IoctlUnicodeControl(struct smb_ioctl *ioctlp, struct cm_user * userp);
+extern afs_int32 cm_IoctlUnicodeControl(struct cm_ioctl *ioctlp, struct cm_user * userp);
 
 #endif /* __CM_IOCTL_INTERFACES_ONLY__ */
 
index d901692..117d51a 100644 (file)
@@ -15,6 +15,7 @@
 #include <string.h>
 
 #include "afsd.h"
+#include "smb.h"
 #include <osi.h>
 #include <rx/rx.h>
 
index 8d53361..7116555 100644 (file)
@@ -21,6 +21,7 @@
 #include <osi.h>
 
 #include "afsd.h"
+#include "smb.h"
 #include "cm_btree.h"
 
 #ifdef DEBUG
index 9ef5047..91fff17 100644 (file)
@@ -1510,10 +1510,10 @@ void smb_ReleaseFID(smb_fid_t *fidp)
         if (ioctlp) {
             if (ioctlp->prefix)
                 cm_FreeSpace(ioctlp->prefix);
-            if (ioctlp->inAllocp)
-                free(ioctlp->inAllocp);
-            if (ioctlp->outAllocp)
-                free(ioctlp->outAllocp);
+            if (ioctlp->ioctl.inAllocp)
+                free(ioctlp->ioctl.inAllocp);
+            if (ioctlp->ioctl.outAllocp)
+                free(ioctlp->ioctl.outAllocp);
             free(ioctlp);
         }       
        lock_ReleaseMutex(&fidp->mx);
index 8718ea4..abb6f69 100644 (file)
@@ -318,38 +318,9 @@ typedef struct smb_pid {
     struct smb_tid *tidp;              /* back ptr */
 } smb_pid_t;
 
-/* ioctl parameter, while being assembled and/or processed */
-typedef struct smb_ioctl {
-    /* input side */
-    char *inDatap;                     /* ioctl func's current position
-                                        * in input parameter block */
-    char *inAllocp;                    /* allocated input parameter block */
-    afs_uint32 inCopied;                       /* # of input bytes copied in so far
-                                        * by write calls */
-    cm_space_t *prefix;                        /* prefix for subst drives */
-    char *tidPathp;                    /* Pathname associated with Tree ID */
-
-    /* output side */
-    char *outDatap;                    /* output results assembled so far */
-    char *outAllocp;                   /* output results assembled so far */
-    afs_uint32 outCopied;              /* # of output bytes copied back so far
-                                         * by read calls */
-       
-    /* flags */
-    afs_uint32 flags;
-
-    /* fid pointer */
-    struct smb_fid *fidp;
-
-    /* uid pointer */
-    smb_user_t *uidp;
-
-} smb_ioctl_t;
-
-/* flags for smb_ioctl_t */
-#define SMB_IOCTLFLAG_DATAIN   1       /* reading data from client to server */
-#define SMB_IOCTLFLAG_LOGON    2       /* got tokens from integrated logon */
-#define SMB_IOCTLFLAG_USEUTF8   4       /* this request is using UTF-8 strings */
+
+/* Defined in smb_ioctl.h */
+struct smb_ioctl;
 
 /* one per file ID; these are really file descriptors */
 typedef struct smb_fid {
@@ -365,7 +336,7 @@ typedef struct smb_fid {
                                            the file if session is
                                            terminated) */
     osi_hyper_t offset;                        /* our file pointer */
-    smb_ioctl_t *ioctlp;               /* ptr to ioctl structure */
+    struct smb_ioctl *ioctlp;          /* ptr to ioctl structure */
                                        /* Under NT, we may need to know the
                                         * parent directory and pathname used
                                         * to open the file, either to delete
@@ -563,6 +534,8 @@ extern smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags);
 
 extern smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags);
 
+extern cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags);
+
 extern smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern); 
 
 extern void smb_ReleaseUsername(smb_username_t *unp);
index 8f73dac..f44d8a2 100644 (file)
@@ -21,7 +21,7 @@ typedef struct chservinfo {
 } chservinfo_t;
 
 struct gaginfo {
-       unsigned long showflags, logflags, logwritethruflag, spare[3];
+       afs_uint32 showflags, logflags, logwritethruflag, spare[3];
         unsigned char spare2[128];
 };
 
@@ -97,5 +97,13 @@ struct sbstruct {
 #define VIOC_UNICODECTL                 0x33
 
 #define VIOC_VOLSTAT_TEST               0x3F
-/* Not to exceed SMB_IOCTL_MAXPROCS from smb_ioctl.h */
+
+/* magic file name for ioctl opens */
+#define CM_IOCTL_FILENAME      "\\_._AFS_IOCTL_._"     /* double backslashes for C compiler */
+#define CM_IOCTL_FILENAME_NOSLASH "_._AFS_IOCTL_._"
+
+/* max parms for ioctl, in either direction */
+#define CM_IOCTL_MAXDATA               8192*2
+#define CM_IOCTL_MAXPROCS               64
+
 #endif /*  __SMB_IOCONS_H_ENV_ */
index 76a9d25..7729816 100644 (file)
@@ -16,6 +16,7 @@
 #include <string.h>
 #include <stdio.h>
 #include <time.h>
+#include <strsafe.h>
 
 #include <osi.h>
 
 
 #include "smb.h"
 
+#include "cm_rpc.h"
+#include "afs/afsrpc.h"
+#include "afs/auth.h"
+
 smb_ioctlProc_t *smb_ioctlProcsp[SMB_IOCTL_MAXPROCS];
 
-/*extern unsigned char smb_LANadapter;*/
-
-void smb_InitIoctl(void)
-{
-        int i;
-        for (i=0; i<SMB_IOCTL_MAXPROCS; i++)
-           smb_ioctlProcsp[i] = NULL;
-
-       smb_ioctlProcsp[VIOCGETAL] = cm_IoctlGetACL;
-        smb_ioctlProcsp[VIOC_FILE_CELL_NAME] = cm_IoctlGetFileCellName;
-        smb_ioctlProcsp[VIOCSETAL] = cm_IoctlSetACL;
-        smb_ioctlProcsp[VIOC_FLUSHVOLUME] = cm_IoctlFlushVolume;
-        smb_ioctlProcsp[VIOCFLUSH] = cm_IoctlFlushFile;
-        smb_ioctlProcsp[VIOCSETVOLSTAT] = cm_IoctlSetVolumeStatus;
-        smb_ioctlProcsp[VIOCGETVOLSTAT] = cm_IoctlGetVolumeStatus;
-        smb_ioctlProcsp[VIOCWHEREIS] = cm_IoctlWhereIs;
-        smb_ioctlProcsp[VIOC_AFS_STAT_MT_PT] = cm_IoctlStatMountPoint;
-        smb_ioctlProcsp[VIOC_AFS_DELETE_MT_PT] = cm_IoctlDeleteMountPoint;
-        smb_ioctlProcsp[VIOCCKSERV] = cm_IoctlCheckServers;
-        smb_ioctlProcsp[VIOC_GAG] = cm_IoctlGag;
-        smb_ioctlProcsp[VIOCCKBACK] = cm_IoctlCheckVolumes;
-        smb_ioctlProcsp[VIOCSETCACHESIZE] = cm_IoctlSetCacheSize;
-        smb_ioctlProcsp[VIOCGETCACHEPARMS] = cm_IoctlGetCacheParms;
-        smb_ioctlProcsp[VIOCGETCELL] = cm_IoctlGetCell;
-        smb_ioctlProcsp[VIOCNEWCELL] = cm_IoctlNewCell;
-        smb_ioctlProcsp[VIOC_GET_WS_CELL] = cm_IoctlGetWsCell;
-        smb_ioctlProcsp[VIOC_AFS_SYSNAME] = cm_IoctlSysName;
-        smb_ioctlProcsp[VIOC_GETCELLSTATUS] = cm_IoctlGetCellStatus;
-        smb_ioctlProcsp[VIOC_SETCELLSTATUS] = cm_IoctlSetCellStatus;
-        smb_ioctlProcsp[VIOC_SETSPREFS] = cm_IoctlSetSPrefs;
-        smb_ioctlProcsp[VIOC_GETSPREFS] = cm_IoctlGetSPrefs;
-        smb_ioctlProcsp[VIOC_STOREBEHIND] = cm_IoctlStoreBehind;
-        smb_ioctlProcsp[VIOC_AFS_CREATE_MT_PT] = cm_IoctlCreateMountPoint;
-        smb_ioctlProcsp[VIOC_TRACECTL] = cm_IoctlTraceControl;
-       smb_ioctlProcsp[VIOCSETTOK] = cm_IoctlSetToken;
-       smb_ioctlProcsp[VIOCGETTOK] = cm_IoctlGetTokenIter;
-       smb_ioctlProcsp[VIOCNEWGETTOK] = cm_IoctlGetToken;
-       smb_ioctlProcsp[VIOCDELTOK] = cm_IoctlDelToken;
-       smb_ioctlProcsp[VIOCDELALLTOK] = cm_IoctlDelAllToken;
-       smb_ioctlProcsp[VIOC_SYMLINK] = cm_IoctlSymlink;
-       smb_ioctlProcsp[VIOC_LISTSYMLINK] = cm_IoctlListlink;
-       smb_ioctlProcsp[VIOC_DELSYMLINK] = cm_IoctlDeletelink;
-       smb_ioctlProcsp[VIOC_MAKESUBMOUNT] = cm_IoctlMakeSubmount;
-       smb_ioctlProcsp[VIOC_GETRXKCRYPT] = cm_IoctlGetRxkcrypt;
-       smb_ioctlProcsp[VIOC_SETRXKCRYPT] = cm_IoctlSetRxkcrypt;
-       smb_ioctlProcsp[VIOC_ISSYMLINK] = cm_IoctlIslink;
-       smb_ioctlProcsp[VIOC_TRACEMEMDUMP] = cm_IoctlMemoryDump;
-       smb_ioctlProcsp[VIOC_ISSYMLINK] = cm_IoctlIslink;
-        smb_ioctlProcsp[VIOC_FLUSHALL] = cm_IoctlFlushAllVolumes;
-        smb_ioctlProcsp[VIOCGETFID] = cm_IoctlGetFid;
-        smb_ioctlProcsp[VIOCGETOWNER] = cm_IoctlGetOwner;
-        smb_ioctlProcsp[VIOC_RXSTAT_PROC] = cm_IoctlRxStatProcess;
-        smb_ioctlProcsp[VIOC_RXSTAT_PEER] = cm_IoctlRxStatPeer;
-        smb_ioctlProcsp[VIOC_UUIDCTL] = cm_IoctlUUIDControl;
-        smb_ioctlProcsp[VIOC_PATH_AVAILABILITY] = cm_IoctlPathAvailability;
-        smb_ioctlProcsp[VIOC_GETFILETYPE] = cm_IoctlGetFileType;
-        smb_ioctlProcsp[VIOC_VOLSTAT_TEST] = cm_IoctlVolStatTest;
-        smb_ioctlProcsp[VIOC_UNICODECTL] = cm_IoctlUnicodeControl;
-}
+void 
+smb_InitIoctl(void)
+{
+    int i;
+    for (i=0; i<SMB_IOCTL_MAXPROCS; i++)
+        smb_ioctlProcsp[i] = NULL;
+
+    smb_ioctlProcsp[VIOCGETAL] = smb_IoctlGetACL;
+    smb_ioctlProcsp[VIOC_FILE_CELL_NAME] = smb_IoctlGetFileCellName;
+    smb_ioctlProcsp[VIOCSETAL] = smb_IoctlSetACL;
+    smb_ioctlProcsp[VIOC_FLUSHVOLUME] = smb_IoctlFlushVolume;
+    smb_ioctlProcsp[VIOCFLUSH] = smb_IoctlFlushFile;
+    smb_ioctlProcsp[VIOCSETVOLSTAT] = smb_IoctlSetVolumeStatus;
+    smb_ioctlProcsp[VIOCGETVOLSTAT] = smb_IoctlGetVolumeStatus;
+    smb_ioctlProcsp[VIOCWHEREIS] = smb_IoctlWhereIs;
+    smb_ioctlProcsp[VIOC_AFS_STAT_MT_PT] = smb_IoctlStatMountPoint;
+    smb_ioctlProcsp[VIOC_AFS_DELETE_MT_PT] = smb_IoctlDeleteMountPoint;
+    smb_ioctlProcsp[VIOCCKSERV] = smb_IoctlCheckServers;
+    smb_ioctlProcsp[VIOC_GAG] = smb_IoctlGag;
+    smb_ioctlProcsp[VIOCCKBACK] = smb_IoctlCheckVolumes;
+    smb_ioctlProcsp[VIOCSETCACHESIZE] = smb_IoctlSetCacheSize;
+    smb_ioctlProcsp[VIOCGETCACHEPARMS] = smb_IoctlGetCacheParms;
+    smb_ioctlProcsp[VIOCGETCELL] = smb_IoctlGetCell;
+    smb_ioctlProcsp[VIOCNEWCELL] = smb_IoctlNewCell;
+    smb_ioctlProcsp[VIOC_GET_WS_CELL] = smb_IoctlGetWsCell;
+    smb_ioctlProcsp[VIOC_AFS_SYSNAME] = smb_IoctlSysName;
+    smb_ioctlProcsp[VIOC_GETCELLSTATUS] = smb_IoctlGetCellStatus;
+    smb_ioctlProcsp[VIOC_SETCELLSTATUS] = smb_IoctlSetCellStatus;
+    smb_ioctlProcsp[VIOC_SETSPREFS] = smb_IoctlSetSPrefs;
+    smb_ioctlProcsp[VIOC_GETSPREFS] = smb_IoctlGetSPrefs;
+    smb_ioctlProcsp[VIOC_STOREBEHIND] = smb_IoctlStoreBehind;
+    smb_ioctlProcsp[VIOC_AFS_CREATE_MT_PT] = smb_IoctlCreateMountPoint;
+    smb_ioctlProcsp[VIOC_TRACECTL] = smb_IoctlTraceControl;
+    smb_ioctlProcsp[VIOCSETTOK] = smb_IoctlSetToken;
+    smb_ioctlProcsp[VIOCGETTOK] = smb_IoctlGetTokenIter;
+    smb_ioctlProcsp[VIOCNEWGETTOK] = smb_IoctlGetToken;
+    smb_ioctlProcsp[VIOCDELTOK] = smb_IoctlDelToken;
+    smb_ioctlProcsp[VIOCDELALLTOK] = smb_IoctlDelAllToken;
+    smb_ioctlProcsp[VIOC_SYMLINK] = smb_IoctlSymlink;
+    smb_ioctlProcsp[VIOC_LISTSYMLINK] = smb_IoctlListlink;
+    smb_ioctlProcsp[VIOC_DELSYMLINK] = smb_IoctlDeletelink;
+    smb_ioctlProcsp[VIOC_MAKESUBMOUNT] = smb_IoctlMakeSubmount;
+    smb_ioctlProcsp[VIOC_GETRXKCRYPT] = smb_IoctlGetRxkcrypt;
+    smb_ioctlProcsp[VIOC_SETRXKCRYPT] = smb_IoctlSetRxkcrypt;
+    smb_ioctlProcsp[VIOC_ISSYMLINK] = smb_IoctlIslink;
+    smb_ioctlProcsp[VIOC_TRACEMEMDUMP] = smb_IoctlMemoryDump;
+    smb_ioctlProcsp[VIOC_ISSYMLINK] = smb_IoctlIslink;
+    smb_ioctlProcsp[VIOC_FLUSHALL] = smb_IoctlFlushAllVolumes;
+    smb_ioctlProcsp[VIOCGETFID] = smb_IoctlGetFid;
+    smb_ioctlProcsp[VIOCGETOWNER] = smb_IoctlGetOwner;
+    smb_ioctlProcsp[VIOC_RXSTAT_PROC] = smb_IoctlRxStatProcess;
+    smb_ioctlProcsp[VIOC_RXSTAT_PEER] = smb_IoctlRxStatPeer;
+    smb_ioctlProcsp[VIOC_UUIDCTL] = smb_IoctlUUIDControl;
+    smb_ioctlProcsp[VIOC_PATH_AVAILABILITY] = smb_IoctlPathAvailability;
+    smb_ioctlProcsp[VIOC_GETFILETYPE] = smb_IoctlGetFileType;
+    smb_ioctlProcsp[VIOC_VOLSTAT_TEST] = smb_IoctlVolStatTest;
+    smb_ioctlProcsp[VIOC_UNICODECTL] = smb_IoctlUnicodeControl;
+}       
 
 /* called to make a fid structure into an IOCTL fid structure */
-void smb_SetupIoctlFid(smb_fid_t *fidp, cm_space_t *prefix)
+void 
+smb_SetupIoctlFid(smb_fid_t *fidp, cm_space_t *prefix)
 {
     smb_ioctl_t *iop;
     cm_space_t *copyPrefix;
@@ -103,7 +108,7 @@ void smb_SetupIoctlFid(smb_fid_t *fidp, cm_space_t *prefix)
     }
     if (prefix) {
         copyPrefix = cm_GetSpace();
-        strcpy(copyPrefix->data, prefix->data);
+        StringCbCopy(copyPrefix->data, CM_UTILS_SPACESIZE, prefix->data);
         fidp->ioctlp->prefix = copyPrefix;
     }
     lock_ReleaseMutex(&fidp->mx);
@@ -113,22 +118,23 @@ void smb_SetupIoctlFid(smb_fid_t *fidp, cm_space_t *prefix)
  * this is the first read call.  This is the function that actually makes the
  * call to the ioctl code.
  */
-long smb_IoctlPrepareRead(smb_fid_t *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp)
+afs_int32
+smb_IoctlPrepareRead(smb_fid_t *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp)
 {
-    long opcode;
+    afs_int32 opcode;
     smb_ioctlProc_t *procp = NULL;
-    long code;
+    afs_int32 code;
 
-    if (ioctlp->flags & SMB_IOCTLFLAG_DATAIN) {
-        ioctlp->flags &= ~SMB_IOCTLFLAG_DATAIN;
+    if (ioctlp->ioctl.flags & CM_IOCTLFLAG_DATAIN) {
+        ioctlp->ioctl.flags &= ~CM_IOCTLFLAG_DATAIN;
 
         /* do the call now, or fail if we didn't get an opcode, or
          * enough of an opcode.
          */
-        if (ioctlp->inCopied < sizeof(long)) 
+        if (ioctlp->ioctl.inCopied < sizeof(afs_int32)) 
             return CM_ERROR_INVAL;
-        memcpy(&opcode, ioctlp->inDatap, sizeof(long));
-        ioctlp->inDatap += sizeof(long);
+        memcpy(&opcode, ioctlp->ioctl.inDatap, sizeof(afs_int32));
+        ioctlp->ioctl.inDatap += sizeof(afs_int32);
 
         osi_Log1(afsd_logp, "Ioctl opcode 0x%x", opcode);
 
@@ -142,13 +148,13 @@ long smb_IoctlPrepareRead(smb_fid_t *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp
             return CM_ERROR_BADOP;
 
         /* otherwise, make the call */
-        ioctlp->outDatap += sizeof(long);      /* reserve room for return code */
+        ioctlp->ioctl.outDatap += sizeof(afs_int32); /* reserve room for return code */
         code = (*procp)(ioctlp, userp);
 
         osi_Log1(afsd_logp, "Ioctl return code 0x%x", code);
 
         /* copy in return code */
-        memcpy(ioctlp->outAllocp, &code, sizeof(long));
+        memcpy(ioctlp->ioctl.outAllocp, &code, sizeof(afs_int32));
     }
     return 0;
 }
@@ -157,176 +163,183 @@ long smb_IoctlPrepareRead(smb_fid_t *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp
  * a series of reads (or the very first call), then we start a new call.
  * We also ensure that things are properly initialized for the start of a call.
  */
-void smb_IoctlPrepareWrite(smb_fid_t *fidp, smb_ioctl_t *ioctlp)
-{
-       /* make sure the buffer(s) are allocated */
-       if (!ioctlp->inAllocp) ioctlp->inAllocp = malloc(SMB_IOCTL_MAXDATA);
-        if (!ioctlp->outAllocp) ioctlp->outAllocp = malloc(SMB_IOCTL_MAXDATA);
-
-       /* Fixes fs la problem.  We do a StrToOEM later and if this data isn't initialized we get memory issues. */
-       (void) memset(ioctlp->inAllocp, 0, SMB_IOCTL_MAXDATA);
-       (void) memset(ioctlp->outAllocp, 0, SMB_IOCTL_MAXDATA);
-
-       /* and make sure that we've reset our state for the new incoming request */
-       if (!(ioctlp->flags & SMB_IOCTLFLAG_DATAIN)) {
-               ioctlp->inCopied = 0;
-               ioctlp->outCopied = 0;
-               ioctlp->inDatap = ioctlp->inAllocp;
-               ioctlp->outDatap = ioctlp->outAllocp;
-               ioctlp->flags |= SMB_IOCTLFLAG_DATAIN;
-       }
-}
+void 
+smb_IoctlPrepareWrite(smb_fid_t *fidp, smb_ioctl_t *ioctlp)
+{
+    /* make sure the buffer(s) are allocated */
+    if (!ioctlp->ioctl.inAllocp) 
+        ioctlp->ioctl.inAllocp = malloc(SMB_IOCTL_MAXDATA);
+    if (!ioctlp->ioctl.outAllocp)
+        ioctlp->ioctl.outAllocp = malloc(SMB_IOCTL_MAXDATA);
+
+    /* Fixes fs la problem.  We do a StrToOEM later and if this data isn't initialized we get memory issues. */
+    (void) memset(ioctlp->ioctl.inAllocp, 0, SMB_IOCTL_MAXDATA);
+    (void) memset(ioctlp->ioctl.outAllocp, 0, SMB_IOCTL_MAXDATA);
+
+    /* and make sure that we've reset our state for the new incoming request */
+    if (!(ioctlp->ioctl.flags & CM_IOCTLFLAG_DATAIN)) {
+        ioctlp->ioctl.inCopied = 0;
+        ioctlp->ioctl.outCopied = 0;
+        ioctlp->ioctl.inDatap = ioctlp->ioctl.inAllocp;
+        ioctlp->ioctl.outDatap = ioctlp->ioctl.outAllocp;
+        ioctlp->ioctl.flags |= CM_IOCTLFLAG_DATAIN;
+    }
+}       
 
 /* called from smb_ReceiveCoreRead when we receive a read on the ioctl fid */
-long smb_IoctlRead(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
-       smb_packet_t *outp)
+afs_int32
+smb_IoctlRead(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
-       smb_ioctl_t *iop;
-        long count;
-        long leftToCopy;
-        char *op;
-        long code;
-        cm_user_t *userp;
+    smb_ioctl_t *iop;
+    long count;
+    afs_int32 leftToCopy;
+    char *op;
+    afs_int32 code;
+    cm_user_t *userp;
 
-        iop = fidp->ioctlp;
-        count = smb_GetSMBParm(inp, 1);
-        userp = smb_GetUserFromVCP(vcp, inp);
+    iop = fidp->ioctlp;
+    count = smb_GetSMBParm(inp, 1);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
-       /* Identify tree */
+    /* Identify tree */
     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
     if(code) {
         cm_ReleaseUser(userp);
         return CM_ERROR_NOSUCHPATH;
     }
 
-       /* turn the connection around, if required */
-       code = smb_IoctlPrepareRead(fidp, iop, userp);
+    /* turn the connection around, if required */
+    code = smb_IoctlPrepareRead(fidp, iop, userp);
+
+    if (code) {
+        cm_ReleaseUser(userp);
+        return code;
+    }
+
+    leftToCopy = (afs_int32)((iop->ioctl.outDatap - iop->ioctl.outAllocp) - iop->ioctl.outCopied);
+    if (count > leftToCopy)
+        count = leftToCopy;
 
-       if (code) {
-               cm_ReleaseUser(userp);
-               return code;
-        }
+    /* now set the parms for a read of count bytes */
+    smb_SetSMBParm(outp, 0, count);
+    smb_SetSMBParm(outp, 1, 0);
+    smb_SetSMBParm(outp, 2, 0);
+    smb_SetSMBParm(outp, 3, 0);
+    smb_SetSMBParm(outp, 4, 0);
 
-       leftToCopy = (long)((iop->outDatap - iop->outAllocp) - iop->outCopied);
-        if (count > leftToCopy) count = leftToCopy;
-        
-        /* now set the parms for a read of count bytes */
-        smb_SetSMBParm(outp, 0, count);
-        smb_SetSMBParm(outp, 1, 0);
-        smb_SetSMBParm(outp, 2, 0);
-        smb_SetSMBParm(outp, 3, 0);
-        smb_SetSMBParm(outp, 4, 0);
+    smb_SetSMBDataLength(outp, count+3);
 
-       smb_SetSMBDataLength(outp, count+3);
+    op = smb_GetSMBData(outp, NULL);
+    *op++ = 1;
+    *op++ = (char)(count & 0xff);
+    *op++ = (char)((count >> 8) & 0xff);
 
-        op = smb_GetSMBData(outp, NULL);
-        *op++ = 1;
-        *op++ = (char)(count & 0xff);
-        *op++ = (char)((count >> 8) & 0xff);
-        
-       /* now copy the data into the response packet */
-        memcpy(op, iop->outCopied + iop->outAllocp, count);
+    /* now copy the data into the response packet */
+    memcpy(op, iop->ioctl.outCopied + iop->ioctl.outAllocp, count);
 
-        /* and adjust the counters */
-        iop->outCopied += count;
-        
-        cm_ReleaseUser(userp);
+    /* and adjust the counters */
+    iop->ioctl.outCopied += count;
+
+    cm_ReleaseUser(userp);
 
-        return 0;
+    return 0;
 }
 
 /* called from smb_ReceiveCoreWrite when we receive a write call on the IOCTL
  * file descriptor.
  */
-long smb_IoctlWrite(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
+afs_int32
+smb_IoctlWrite(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
-       smb_ioctl_t *iop;
-        long count;
-        long code;
-        char *op;
-        int inDataBlockCount;
+    smb_ioctl_t *iop;
+    long count;
+    afs_int32 code;
+    char *op;
+    int inDataBlockCount;
 
-       code = 0;
-       count = smb_GetSMBParm(inp, 1);
-        iop = fidp->ioctlp;
+    code = 0;
+    count = smb_GetSMBParm(inp, 1);
+    iop = fidp->ioctlp;
         
-       smb_IoctlPrepareWrite(fidp, iop);
+    smb_IoctlPrepareWrite(fidp, iop);
 
-        op = smb_GetSMBData(inp, NULL);
-       op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
+    op = smb_GetSMBData(inp, NULL);
+    op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
        
-        if (count + iop->inCopied > SMB_IOCTL_MAXDATA) {
-               code = CM_ERROR_TOOBIG;
-                goto done;
-        }
+    if (count + iop->ioctl.inCopied > SMB_IOCTL_MAXDATA) {
+        code = CM_ERROR_TOOBIG;
+        goto done;
+    }
         
-       /* copy data */
-        memcpy(iop->inDatap + iop->inCopied, op, count);
+    /* copy data */
+    memcpy(iop->ioctl.inDatap + iop->ioctl.inCopied, op, count);
         
-        /* adjust counts */
-        iop->inCopied += count;
-
-done:
-       /* return # of bytes written */
-       if (code == 0) {
-               smb_SetSMBParm(outp, 0, count);
-                smb_SetSMBDataLength(outp, 0);
-        }
+    /* adjust counts */
+    iop->ioctl.inCopied += count;
 
-        return code;
-}
+  done:
+    /* return # of bytes written */
+    if (code == 0) {
+        smb_SetSMBParm(outp, 0, count);
+        smb_SetSMBDataLength(outp, 0);
+    }
+
+    return code;
+}       
 
 /* called from smb_ReceiveV3WriteX when we receive a write call on the IOCTL
  * file descriptor.
  */
-long smb_IoctlV3Write(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
+afs_int32
+smb_IoctlV3Write(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
-       smb_ioctl_t *iop;
-        long count;
-        long code;
-        char *op;
-        int inDataBlockCount;
+    smb_ioctl_t *iop;
+    long count;
+    afs_int32 code;
+    char *op;
+    int inDataBlockCount;
 
-       code = 0;
-       count = smb_GetSMBParm(inp, 10);
-        iop = fidp->ioctlp;
-        
-       smb_IoctlPrepareWrite(fidp, iop);
+    code = 0;
+    count = smb_GetSMBParm(inp, 10);
+    iop = fidp->ioctlp;
 
-        op = inp->data + smb_GetSMBParm(inp, 11);
-        inDataBlockCount = count;
-       
-        if (count + iop->inCopied > SMB_IOCTL_MAXDATA) {
-               code = CM_ERROR_TOOBIG;
-                goto done;
-        }
-        
-       /* copy data */
-        memcpy(iop->inDatap + iop->inCopied, op, count);
+    smb_IoctlPrepareWrite(fidp, iop);
+
+    op = inp->data + smb_GetSMBParm(inp, 11);
+    inDataBlockCount = count;
+
+    if (count + iop->ioctl.inCopied > SMB_IOCTL_MAXDATA) {
+        code = CM_ERROR_TOOBIG;
+        goto done;
+    }
         
-        /* adjust counts */
-        iop->inCopied += count;
-
-done:
-       /* return # of bytes written */
-       if (code == 0) {
-               smb_SetSMBParm(outp, 2, count);
-                smb_SetSMBParm(outp, 3, 0); /* reserved */
-               smb_SetSMBParm(outp, 4, 0); /* reserved */
-               smb_SetSMBParm(outp, 5, 0); /* reserved */
-               smb_SetSMBDataLength(outp, 0);
-        }
+    /* copy data */
+    memcpy(iop->ioctl.inDatap + iop->ioctl.inCopied, op, count);
+
+    /* adjust counts */
+    iop->ioctl.inCopied += count;
+
+  done:
+    /* return # of bytes written */
+    if (code == 0) {
+        smb_SetSMBParm(outp, 2, count);
+        smb_SetSMBParm(outp, 3, 0); /* reserved */
+        smb_SetSMBParm(outp, 4, 0); /* reserved */
+        smb_SetSMBParm(outp, 5, 0); /* reserved */
+        smb_SetSMBDataLength(outp, 0);
+    }
 
-        return code;
-}
+    return code;
+}       
 
 
 /* called from V3 read to handle IOCTL descriptor reads */
-long smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
+afs_int32
+smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     smb_ioctl_t *iop;
     long count;
-    long code;
+    afs_int32 code;
     long leftToCopy;
     char *op;
     cm_user_t *userp;
@@ -341,8 +354,8 @@ long smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     iop->uidp = uidp;
     if (uidp && uidp->unp) {
         osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s",
-                  uidp->userID, userp,
-                  osi_LogSaveString(afsd_logp, uidp->unp->name));
+                 uidp->userID, userp,
+                 osi_LogSaveString(afsd_logp, uidp->unp->name));
     } else {
         if (uidp)
            osi_Log2(afsd_logp, "Ioctl uid %d user %x no name",
@@ -370,8 +383,9 @@ long smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_pack
        return code;
     }
 
-    leftToCopy = (long)((iop->outDatap - iop->outAllocp) - iop->outCopied);
-    if (count > leftToCopy) count = leftToCopy;
+    leftToCopy = (long)((iop->ioctl.outDatap - iop->ioctl.outAllocp) - iop->ioctl.outCopied);
+    if (count > leftToCopy) 
+        count = leftToCopy;
         
     /* 0 and 1 are reserved for request chaining, were setup by our caller,
      * and will be further filled in after we return.
@@ -399,10 +413,10 @@ long smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     smb_SetSMBDataLength(outp, count);
         
     /* now copy the data into the response packet */
-    memcpy(op, iop->outCopied + iop->outAllocp, count);
+    memcpy(op, iop->ioctl.outCopied + iop->ioctl.outAllocp, count);
 
     /* and adjust the counters */
-    iop->outCopied += count;
+    iop->ioctl.outCopied += count;
 
     /* and cleanup things */
     cm_ReleaseUser(userp);
@@ -411,53 +425,49 @@ long smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_pack
 }      
 
 /* called from Read Raw to handle IOCTL descriptor reads */
-long smb_IoctlReadRaw(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
-                     smb_packet_t *outp
-                     )
+afs_int32
+smb_IoctlReadRaw(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
+                 smb_packet_t *outp)
 {
     smb_ioctl_t *iop;
     long leftToCopy;
     NCB *ncbp;
-    long code;
+    afs_int32 code;
     cm_user_t *userp;
+    smb_user_t *uidp;
 
     iop = fidp->ioctlp;
 
     userp = smb_GetUserFromVCP(vcp, inp);
 
     /* Log the user */
-    {
-       smb_user_t *uidp;
-
-       uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
-       if (uidp && uidp->unp) {
-           osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s",
-                    uidp->userID, userp,
-                    osi_LogSaveString(afsd_logp, uidp->unp->name));
-       } else if (uidp) {
-           osi_Log2(afsd_logp, "Ioctl uid %d user %x no name",
-                    uidp->userID, userp);
-       } else {
-           osi_Log1(afsd_logp, "Ioctl no uid user %x no name",
-                    userp);
-       }
-       if (uidp) 
-           smb_ReleaseUID(uidp);
-    }  
+    uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
+    if (uidp && uidp->unp) {
+        osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s",
+                  uidp->userID, userp,
+                  osi_LogSaveString(afsd_logp, uidp->unp->name));
+    } else if (uidp) {
+        osi_Log2(afsd_logp, "Ioctl uid %d user %x no name",
+                  uidp->userID, userp);
+    } else {
+        osi_Log1(afsd_logp, "Ioctl no uid user %x no name",
+                  userp);
+    }
+    if (uidp) 
+        smb_ReleaseUID(uidp);
 
     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
     if (code) {
-        cm_ReleaseUser(userp);
-        return CM_ERROR_NOSUCHPATH;
+        code = CM_ERROR_NOSUCHPATH;
+        goto done;
     }
 
     code = smb_IoctlPrepareRead(fidp, iop, userp);
     if (code) {
-       cm_ReleaseUser(userp);
-       return code;
+        goto done;
     }
 
-    leftToCopy = (long)((iop->outDatap - iop->outAllocp) - iop->outCopied);
+    leftToCopy = (long)((iop->ioctl.outDatap - iop->ioctl.outAllocp) - iop->ioctl.outCopied);
 
     ncbp = outp->ncbp;
     memset((char *)ncbp, 0, sizeof(NCB));
@@ -468,13 +478,1317 @@ long smb_IoctlReadRaw(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
     /*ncbp->ncb_lana_num = smb_LANadapter;*/
     ncbp->ncb_lana_num = vcp->lana;
 
-    ncbp->ncb_buffer = iop->outCopied + iop->outAllocp;
+    ncbp->ncb_buffer = iop->ioctl.outCopied + iop->ioctl.outAllocp;
     code = Netbios(ncbp);
 
     if (code != 0)
        osi_Log1(afsd_logp, "ReadRaw send failure code %d", code);
 
+  done:
     cm_ReleaseUser(userp);
 
+    return code;
+}
+
+/* parse the passed-in file name and do a namei on it.  If we fail,
+ * return an error code, otherwise return the vnode located in *scpp.
+ */
+#define CM_PARSE_FLAG_LITERAL 1
+
+afs_int32
+smb_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
+                   cm_scache_t **scpp, afs_uint32 flags)
+{
+    afs_int32 code;
+    cm_scache_t *substRootp = NULL;
+    cm_scache_t *iscp = NULL;
+    char * relativePath;
+    char * lastComponent = NULL;
+    afs_uint32 follow = (flags & CM_PARSE_FLAG_LITERAL ? CM_FLAG_NOMOUNTCHASE : CM_FLAG_FOLLOW);
+    int free_path = FALSE;
+
+    relativePath = ioctlp->ioctl.inDatap;
+    /* setup the next data value for the caller to use */
+    ioctlp->ioctl.inDatap += (long)strlen(ioctlp->ioctl.inDatap) + 1;;
+
+    osi_Log1(afsd_logp, "smb_ParseIoctlPath %s", osi_LogSaveString(afsd_logp,relativePath));
+
+    /* This is usually the file name, but for StatMountPoint it is the path. */
+    /* ioctlp->inDatap can be either of the form:
+     *    \path\.
+     *    \path\file
+     *    \\netbios-name\submount\path\.
+     *    \\netbios-name\submount\path\file
+     */
+
+       /* We do not perform path name translation on the ioctl path data 
+        * because these paths were not translated by Windows through the
+        * file system API.  Therefore, they are not OEM characters but 
+        * whatever the display character set is.
+        */
+
+    // TranslateExtendedChars(relativePath);
+
+    /* This is usually nothing, but for StatMountPoint it is the file name. */
+    // TranslateExtendedChars(ioctlp->ioctl.inDatap);
+
+    /* If the string starts with our UTF-8 prefix (which is the
+       sequence [ESC,'%','G'] as used by ISO-2022 to designate UTF-8
+       strings), we assume that the provided path is UTF-8.  Otherwise
+       we have to convert the string to UTF-8, since that is what we
+       want to use everywhere else.*/
+
+    if (memcmp(relativePath, utf8_prefix, utf8_prefix_size) == 0) {
+        int len, normalized_len;
+        char * normalized_path;
+
+        /* String is UTF-8 */
+        relativePath += utf8_prefix_size;
+        ioctlp->ioctl.flags |= CM_IOCTLFLAG_USEUTF8;
+
+        len = (ioctlp->ioctl.inDatap - relativePath);
+
+        normalized_len = cm_NormalizeUtf8String(relativePath, len, NULL, 0);
+
+        if (normalized_len > len) {
+            normalized_path = malloc(normalized_len);
+            free_path = TRUE;
+        } else {
+            normalized_path = relativePath;
+        }
+
+        cm_NormalizeUtf8String(relativePath, len, normalized_path, normalized_len);
+
+        if (normalized_path != relativePath)
+            relativePath = normalized_path;
+    } else {
+        /* Not a UTF-8 string */
+        /* TODO: If this is an OEM string, we should convert it to
+           UTF-8. */
+    }
+
+    if (relativePath[0] == relativePath[1] &&
+         relativePath[1] == '\\' && 
+         !_strnicmp(cm_NetbiosName,relativePath+2,strlen(cm_NetbiosName))) 
+    {
+        char shareName[256];
+        char *sharePath;
+        int shareFound, i;
+
+        /* We may have found a UNC path. 
+         * If the first component is the NetbiosName,
+         * then throw out the second component (the submount)
+         * since it had better expand into the value of ioctl->tidPathp
+         */
+        char * p;
+        p = relativePath + 2 + strlen(cm_NetbiosName) + 1;                     /* buffer overflow vuln.? */
+        if ( !_strnicmp("all", p, 3) )
+            p += 4;
+
+        for (i = 0; *p && *p != '\\'; i++,p++ ) {
+            shareName[i] = *p;
+        }
+        p++;                    /* skip past trailing slash */
+        shareName[i] = 0;       /* terminate string */
+
+        shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
+        if ( shareFound ) {
+            /* we found a sharename, therefore use the resulting path */
+            code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
+                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                             userp, sharePath, reqp, &substRootp);
+            free(sharePath);
+            if (code) {
+               osi_Log1(afsd_logp,"smb_ParseIoctlPath [1] code 0x%x", code);
+                if (free_path)
+                    free(relativePath);
+                return code;
+           }
+
+           lastComponent = strrchr(p, '\\');
+           if (lastComponent && (lastComponent - p) > 1 &&strlen(lastComponent) > 1) {
+               *lastComponent = '\0';
+               lastComponent++;
+
+               code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                                userp, NULL, reqp, &iscp);
+               if (code == 0)
+                   code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
+                                   userp, NULL, reqp, scpp);
+               if (iscp)
+                   cm_ReleaseSCache(iscp);
+           } else {
+               code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
+                               userp, NULL, reqp, scpp);
+           }
+           cm_ReleaseSCache(substRootp);
+            if (code) {
+               osi_Log1(afsd_logp,"smb_ParseIoctlPath [2] code 0x%x", code);
+                if (free_path)
+                    free(relativePath);
+                return code;
+           }
+        } else {
+            /* otherwise, treat the name as a cellname mounted off the afs root.
+             * This requires that we reconstruct the shareName string with 
+             * leading and trailing slashes.
+             */
+            p = relativePath + 2 + strlen(cm_NetbiosName) + 1;
+            if ( !_strnicmp("all", p, 3) )
+                p += 4;
+
+            shareName[0] = '/';
+            for (i = 1; *p && *p != '\\'; i++,p++ ) {
+                shareName[i] = *p;
+            }
+            p++;                    /* skip past trailing slash */
+            shareName[i++] = '/';      /* add trailing slash */
+            shareName[i] = 0;       /* terminate string */
+
+
+            code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
+                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                             userp, shareName, reqp, &substRootp);
+            if (code) {
+               osi_Log1(afsd_logp,"smb_ParseIoctlPath [3] code 0x%x", code);
+                if (free_path)
+                    free(relativePath);
+                return code;
+           }
+
+           lastComponent = strrchr(p, '\\');
+           if (lastComponent && (lastComponent - p) > 1 &&strlen(lastComponent) > 1) {
+               *lastComponent = '\0';
+               lastComponent++;
+
+               code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                                userp, NULL, reqp, &iscp);
+               if (code == 0)
+                   code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
+                                   userp, NULL, reqp, scpp);
+               if (iscp)
+                   cm_ReleaseSCache(iscp);
+           } else {
+               code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
+                               userp, NULL, reqp, scpp);
+           }
+
+           if (code) {
+               cm_ReleaseSCache(substRootp);
+               osi_Log1(afsd_logp,"smb_ParseIoctlPath code [4] 0x%x", code);
+                if (free_path)
+                    free(relativePath);
+                return code;
+           }
+        }
+    } else {
+        code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
+                         CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                         userp, ioctlp->tidPathp, reqp, &substRootp);
+        if (code) {
+           osi_Log1(afsd_logp,"smb_ParseIoctlPath [6] code 0x%x", code);
+            if (free_path)
+                free(relativePath);
+            return code;
+       }
+        
+       lastComponent = strrchr(relativePath, '\\');
+       if (lastComponent && (lastComponent - relativePath) > 1 && strlen(lastComponent) > 1) {
+           *lastComponent = '\0';
+           lastComponent++;
+
+           code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                            userp, NULL, reqp, &iscp);
+           if (code == 0)
+               code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
+                                userp, NULL, reqp, scpp);
+           if (iscp)
+               cm_ReleaseSCache(iscp);
+       } else {
+           code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | follow,
+                            userp, NULL, reqp, scpp);
+       }
+        if (code) {
+           cm_ReleaseSCache(substRootp);
+           osi_Log1(afsd_logp,"smb_ParseIoctlPath [7] code 0x%x", code);
+            if (free_path)
+                free(relativePath);
+            return code;
+       }
+    }
+
+    if (substRootp)
+       cm_ReleaseSCache(substRootp);
+
+    /* and return success */
+    osi_Log1(afsd_logp,"smb_ParseIoctlPath [8] code 0x%x", code);
+
+    if (free_path)
+        free(relativePath);
+    return 0;
+}
+
+
+
+#define LEAF_SIZE 256
+/* parse the passed-in file name and do a namei on its parent.  If we fail,
+ * return an error code, otherwise return the vnode located in *scpp.
+ */
+afs_int32
+smb_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
+                     cm_scache_t **scpp, char *leafp)
+{
+    afs_int32 code;
+    char tbuffer[1024];
+    char *tp, *jp;
+    cm_scache_t *substRootp = NULL;
+    char *inpathp;
+    int free_path = FALSE;
+
+    inpathp = ioctlp->ioctl.inDatap;
+
+    /* If the string starts with our UTF-8 prefix (which is the
+       sequence [ESC,'%','G'] as used by ISO-2022 to designate UTF-8
+       strings), we assume that the provided path is UTF-8.  Otherwise
+       we have to convert the string to UTF-8, since that is what we
+       want to use everywhere else.*/
+
+    if (memcmp(inpathp, utf8_prefix, utf8_prefix_size) == 0) {
+        int len, normalized_len;
+        char * normalized_path;
+
+        /* String is UTF-8 */
+        inpathp += utf8_prefix_size;
+        ioctlp->ioctl.flags |= CM_IOCTLFLAG_USEUTF8;
+
+        len = strlen(inpathp) + 1;
+
+        normalized_len = cm_NormalizeUtf8String(inpathp, len, NULL, 0);
+
+        if (normalized_len > len) {
+            normalized_path = malloc(normalized_len);
+            free_path = TRUE;
+        } else {
+            normalized_path = inpathp;
+        }
+
+        cm_NormalizeUtf8String(inpathp, len, normalized_path, normalized_len);
+
+        if (normalized_path != inpathp)
+            inpathp = normalized_path;
+    } else {
+        /* Not a UTF-8 string */
+        /* TODO: If this is an OEM string, we should convert it to
+           UTF-8. */
+    }
+
+    StringCbCopyA(tbuffer, sizeof(tbuffer), inpathp);
+    tp = strrchr(tbuffer, '\\');
+    jp = strrchr(tbuffer, '/');
+    if (!tp)
+        tp = jp;
+    else if (jp && (tp - tbuffer) < (jp - tbuffer))
+        tp = jp;
+    if (!tp) {
+        StringCbCopyA(tbuffer, sizeof(tbuffer), "\\");
+        if (leafp) 
+            StringCbCopyA(leafp, LEAF_SIZE, inpathp);
+    }
+    else {
+        *tp = 0;
+        if (leafp) 
+            StringCbCopyA(leafp, LEAF_SIZE, tp+1);
+    }   
+
+    if (free_path)
+        free(inpathp);
+    inpathp = NULL;             /* We don't need this from this point on */
+
+    if (free_path)
+        free(inpathp);
+    inpathp = NULL;             /* We don't need this from this point on */
+
+    if (tbuffer[0] == tbuffer[1] &&
+        tbuffer[1] == '\\' && 
+        !_strnicmp(cm_NetbiosName,tbuffer+2,strlen(cm_NetbiosName))) 
+    {
+        char shareName[256];
+        char *sharePath;
+        int shareFound, i;
+
+        /* We may have found a UNC path. 
+         * If the first component is the NetbiosName,
+         * then throw out the second component (the submount)
+         * since it had better expand into the value of ioctl->tidPathp
+         */
+        char * p;
+        p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
+        if ( !_strnicmp("all", p, 3) )
+            p += 4;
+
+        for (i = 0; *p && *p != '\\'; i++,p++ ) {
+            shareName[i] = *p;
+        }
+        p++;                    /* skip past trailing slash */
+        shareName[i] = 0;       /* terminate string */
+
+        shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
+        if ( shareFound ) {
+            /* we found a sharename, therefore use the resulting path */
+            code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
+                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                             userp, sharePath, reqp, &substRootp);
+            free(sharePath);
+            if (code) return code;
+
+            code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                             userp, NULL, reqp, scpp);
+           cm_ReleaseSCache(substRootp);
+            if (code) return code;
+        } else {
+            /* otherwise, treat the name as a cellname mounted off the afs root.
+             * This requires that we reconstruct the shareName string with 
+             * leading and trailing slashes.
+             */
+            p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
+            if ( !_strnicmp("all", p, 3) )
+                p += 4;
+
+            shareName[0] = '/';
+            for (i = 1; *p && *p != '\\'; i++,p++ ) {
+                shareName[i] = *p;
+            }
+            p++;                    /* skip past trailing slash */
+            shareName[i++] = '/';      /* add trailing slash */
+            shareName[i] = 0;       /* terminate string */
+
+            code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
+                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                             userp, shareName, reqp, &substRootp);
+            if (code) return code;
+
+            code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                            userp, NULL, reqp, scpp);
+           cm_ReleaseSCache(substRootp);
+            if (code) return code;
+        }
+    } else {
+        code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
+                        CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                        userp, ioctlp->tidPathp, reqp, &substRootp);
+        if (code) return code;
+
+        code = cm_NameI(substRootp, tbuffer, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                        userp, NULL, reqp, scpp);
+       cm_ReleaseSCache(substRootp);
+        if (code) return code;
+    }
+
+    /* # of bytes of path */
+    code = (long)strlen(ioctlp->ioctl.inDatap) + 1;
+    ioctlp->ioctl.inDatap += code;
+
+    /* and return success */
+    return 0;
+}
+
+afs_int32 
+smb_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    char *saveDataPtr;
+    char *tp;
+    int ticketLen;
+    char *ticket;
+    int ctSize;
+    struct ClearToken ct;
+    cm_cell_t *cellp;
+    cm_ucell_t *ucellp;
+    char *uname = NULL;
+    afs_uuid_t uuid;
+    int flags;
+    char sessionKey[8];
+    char *smbname;
+    int release_userp = 0;
+    char * wdir = NULL;
+
+    saveDataPtr = ioctlp->ioctl.inDatap;
+
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    tp = ioctlp->ioctl.inDatap;
+
+    /* ticket length */
+    memcpy(&ticketLen, tp, sizeof(ticketLen));
+    tp += sizeof(ticketLen);
+    if (ticketLen < MINKTCTICKETLEN || ticketLen > MAXKTCTICKETLEN)
+        return CM_ERROR_INVAL;
+
+    /* remember ticket and skip over it for now */
+    ticket = tp;
+    tp += ticketLen;
+
+    /* clear token size */
+    memcpy(&ctSize, tp, sizeof(ctSize));
+    tp += sizeof(ctSize);
+    if (ctSize != sizeof(struct ClearToken))
+        return CM_ERROR_INVAL;
+
+    /* clear token */
+    memcpy(&ct, tp, ctSize);
+    tp += ctSize;
+    if (ct.AuthHandle == -1)
+        ct.AuthHandle = 999;   /* more rxvab compat stuff */
+
+    /* more stuff, if any */
+    if (ioctlp->ioctl.inCopied > tp - saveDataPtr) {
+        /* flags:  logon flag */
+        memcpy(&flags, tp, sizeof(int));
+        tp += sizeof(int);
+
+        /* cell name */
+        cellp = cm_GetCell(tp, CM_FLAG_CREATE | CM_FLAG_NOPROBE);
+        if (!cellp) 
+            return CM_ERROR_NOSUCHCELL;
+        tp += strlen(tp) + 1;
+
+        /* user name */
+        uname = tp;
+        tp += strlen(tp) + 1;
+
+        if (flags & PIOCTL_LOGON) {
+            /* SMB user name with which to associate tokens */
+            smbname = tp;
+            osi_Log2(smb_logp,"cm_IoctlSetToken for user [%s] smbname [%s]",
+                     osi_LogSaveString(smb_logp,uname), osi_LogSaveString(smb_logp,smbname));
+            fprintf(stderr, "SMB name = %s\n", smbname);
+            tp += strlen(tp) + 1;
+        } else {
+            osi_Log1(smb_logp,"cm_IoctlSetToken for user [%s]",
+                     osi_LogSaveString(smb_logp, uname));
+        }
+
+               /* uuid */
+        memcpy(&uuid, tp, sizeof(uuid));
+        if (!cm_FindTokenEvent(uuid, sessionKey))
+            return CM_ERROR_INVAL;
+    } else {
+        cellp = cm_data.rootCellp;
+        osi_Log0(smb_logp,"cm_IoctlSetToken - no name specified");
+    }
+
+    if (flags & PIOCTL_LOGON) {
+        userp = smb_FindCMUserByName(smbname, ioctlp->fidp->vcp->rname,
+                                    SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON);
+       release_userp = 1;
+    }
+
+    /* store the token */
+    lock_ObtainMutex(&userp->mx);
+    ucellp = cm_GetUCell(userp, cellp);
+    osi_Log1(smb_logp,"cm_IoctlSetToken ucellp %lx", ucellp);
+    ucellp->ticketLen = ticketLen;
+    if (ucellp->ticketp)
+        free(ucellp->ticketp); /* Discard old token if any */
+    ucellp->ticketp = malloc(ticketLen);
+    memcpy(ucellp->ticketp, ticket, ticketLen);
+    /*
+     * Get the session key from the RPC, rather than from the pioctl.
+     */
+    /*
+    memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
+    */
+    memcpy(ucellp->sessionKey.data, sessionKey, sizeof(sessionKey));
+    ucellp->kvno = ct.AuthHandle;
+    ucellp->expirationTime = ct.EndTimestamp;
+    ucellp->gen++;
+#ifdef QUERY_AFSID
+    ucellp->uid = ANONYMOUSID;
+#endif
+    if (uname) {
+        StringCbCopyA(ucellp->userName, MAXKTCNAMELEN, uname);
+#ifdef QUERY_AFSID
+       cm_UsernameToId(uname, ucellp, &ucellp->uid);
+#endif
+    }
+    ucellp->flags |= CM_UCELLFLAG_RXKAD;
+    lock_ReleaseMutex(&userp->mx);
+
+    if (flags & PIOCTL_LOGON) {
+        ioctlp->ioctl.flags |= CM_IOCTLFLAG_LOGON;
+    }
+
+    cm_ResetACLCache(userp);
+
+    if (release_userp)
+       cm_ReleaseUser(userp);
+
+    return 0;
+}
+
+
+
+afs_int32
+smb_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp)
+{
+    smb_user_t *uidp = ioctlp->uidp;
+
+    if (uidp && uidp->unp) {
+        memcpy(ioctlp->ioctl.outDatap, uidp->unp->name, strlen(uidp->unp->name));
+        ioctlp->ioctl.outDatap += strlen(uidp->unp->name);
+    }
+
+    return 0;
+}
+
+afs_int32 
+smb_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
+{
+    cm_scache_t *scp;
+    afs_int32 code;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code) 
+        return code;
+
+    code = cm_IoctlGetACL(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+    return code;
+}
+
+afs_int32 
+smb_IoctlSetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
+{
+    cm_scache_t *scp;
+    afs_int32 code;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code) 
+        return code;
+
+    code = cm_IoctlSetACL(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+    return code;
+}
+
+afs_int32
+smb_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code) 
+        return code;
+
+    code = cm_IoctlGetFileCellName(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+afs_int32 
+smb_IoctlFlushAllVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);  /* we don't care about the path */
+
+    return cm_IoctlFlushAllVolumes(&ioctlp->ioctl, userp);
+}
+
+afs_int32 
+smb_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code) 
+        return code;
+
+    code = cm_IoctlFlushVolume(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+afs_int32 
+smb_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+       cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code) 
+        return code;
+
+    code = cm_IoctlFlushFile(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+    return code;
+}
+
+afs_int32 
+smb_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, 0);
+    if (code) return code;
+
+    code = cm_IoctlSetVolumeStatus(&ioctlp->ioctl, userp, scp, &req);
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+afs_int32 
+smb_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code) 
+        return code;
+
+    code = cm_IoctlGetVolumeStatus(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+afs_int32 
+smb_IoctlGetFid(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t * optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    if (code) 
+        return code;
+
+    code = cm_IoctlGetFid(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+afs_int32 
+smb_IoctlGetFileType(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t * optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code) 
+        return code;
+
+    code = cm_IoctlGetFileType(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+afs_int32 
+smb_IoctlGetOwner(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code) 
+        return code;
+
+    code = cm_IoctlGetOwner(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+afs_int32 
+smb_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code) 
+        return code;
+
+    code = cm_IoctlWhereIs(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+
+afs_int32 
+smb_IoctlStatMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    afs_int32 code;
+    cm_scache_t *dscp;
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    code = smb_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
+    if (code)
+        return code;
+
+    code = cm_IoctlStatMountPoint(&ioctlp->ioctl, userp, dscp, &req);
+
+    cm_ReleaseSCache(dscp);
+
+    return code;
+}
+
+afs_int32 
+smb_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    afs_int32 code;
+    cm_scache_t *dscp;
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    code = smb_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
+    if (code) 
+        return code;
+
+    code = cm_IoctlDeleteMountPoint(&ioctlp->ioctl, userp, dscp, &req);
+
+    cm_ReleaseSCache(dscp);
+
+    return code;
+}
+
+afs_int32 
+smb_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);  /* we don't care about the path */
+
+    return cm_IoctlCheckServers(&ioctlp->ioctl, userp);
+}
+
+afs_int32 
+smb_IoctlGag(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    /* we don't print anything superfluous, so we don't support the gag call */
+    return CM_ERROR_INVAL;
+}
+
+afs_int32 
+smb_IoctlCheckVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlCheckVolumes(&ioctlp->ioctl, userp);
+}
+
+afs_int32 smb_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlSetCacheSize(&ioctlp->ioctl, userp);
+}
+
+
+afs_int32 
+smb_IoctlTraceControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+       
+    return cm_IoctlTraceControl(&ioctlp->ioctl, userp);
+}
+
+afs_int32 
+smb_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+       
+    return cm_IoctlGetCacheParms(&ioctlp->ioctl, userp);
+}
+
+afs_int32 
+smb_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlGetCell(&ioctlp->ioctl, userp);
+}
+
+afs_int32 
+smb_IoctlNewCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlNewCell(&ioctlp->ioctl, userp);
+}
+
+afs_int32 
+smb_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlGetWsCell(&ioctlp->ioctl, userp);
+}
+
+afs_int32 
+smb_IoctlSysName(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlSysName(&ioctlp->ioctl, userp);
+}
+
+afs_int32 
+smb_IoctlGetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlGetCellStatus(&ioctlp->ioctl, userp);
+}
+
+afs_int32 
+smb_IoctlSetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlSetCellStatus(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+smb_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlSetSPrefs(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+smb_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlGetSPrefs(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+smb_IoctlStoreBehind(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    /* we ignore default asynchrony since we only have one way
+     * of doing this today.
+     */
     return 0;
+}       
+
+afs_int32
+smb_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    afs_int32 code;
+    cm_scache_t *dscp;
+    char leaf[LEAF_SIZE];
+    cm_req_t req;
+
+    cm_InitReq(&req);
+        
+    code = smb_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
+    if (code) 
+        return code;
+
+    code = cm_IoctlCreateMountPoint(&ioctlp->ioctl, userp, dscp, &req, leaf);
+
+    cm_ReleaseSCache(dscp);
+    return code;
+}
+
+afs_int32
+smb_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    afs_int32 code;
+    cm_scache_t *dscp;
+    char leaf[LEAF_SIZE];
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    code = smb_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
+    if (code) return code;
+
+    code = cm_IoctlSymlink(&ioctlp->ioctl, userp, dscp, &req, leaf);
+
+    cm_ReleaseSCache(dscp);
+
+    return code;
+}
+
+afs_int32 
+smb_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    afs_int32 code;
+    cm_scache_t *dscp;
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    code = smb_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
+    if (code) return code;
+
+    code = cm_IoctlListlink(&ioctlp->ioctl, userp, dscp, &req);
+
+    cm_ReleaseSCache(dscp);
+    return code;
+}
+
+afs_int32 
+smb_IoctlIslink(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{/*CHECK FOR VALID SYMLINK*/
+    afs_int32 code;
+    cm_scache_t *dscp;
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    code = smb_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
+    if (code) return code;
+
+    code = cm_IoctlIslink(&ioctlp->ioctl, userp, dscp, &req);
+
+    cm_ReleaseSCache(dscp);
+
+    return code;
+}
+
+afs_int32 
+smb_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    afs_int32 code;
+    cm_scache_t *dscp;
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    code = smb_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
+    if (code) return code;
+
+    code = cm_IoctlDeletelink(&ioctlp->ioctl, userp, dscp, &req);
+
+    cm_ReleaseSCache(dscp);
+
+    return code;
+}
+
+afs_int32 
+smb_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlGetTokenIter(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+smb_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlGetToken(&ioctlp->ioctl, userp);
+}
+
+
+afs_int32
+smb_IoctlDelToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlDelToken(&ioctlp->ioctl, userp);
+}
+
+
+afs_int32
+smb_IoctlDelAllToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlDelAllToken(&ioctlp->ioctl, userp);
+}
+
+
+afs_int32
+smb_IoctlMakeSubmount(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlMakeSubmount(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+smb_IoctlGetRxkcrypt(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlGetRxkcrypt(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+smb_IoctlSetRxkcrypt(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlSetRxkcrypt(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+smb_IoctlRxStatProcess(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlRxStatProcess(&ioctlp->ioctl, userp);
+}
+
+
+afs_int32
+smb_IoctlRxStatPeer(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlRxStatPeer(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+smb_IoctlUnicodeControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlUnicodeControl(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+smb_IoctlUUIDControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlUUIDControl(&ioctlp->ioctl, userp);
+}
+
+
+afs_int32
+smb_IoctlMemoryDump(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlMemoryDump(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+smb_IoctlPathAvailability(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code) 
+        return code;
+
+    code = cm_IoctlPathAvailability(&ioctlp->ioctl, userp, scp, &req);
+    cm_ReleaseSCache(scp);
+    return code;
+}
+
+afs_int32
+smb_IoctlVolStatTest(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlVolStatTest(&ioctlp->ioctl, userp);
 }
index ce7f3b1..a9f0c82 100644 (file)
 #ifndef __SMB_IOCTL_H_ENV__
 #define __SMB_IOCTL_H_ENV__ 1
 
+#include <cm_ioctl.h>
+
 /* magic file name for ioctl opens */
-#define SMB_IOCTL_FILENAME     "\\_._AFS_IOCTL_._"     /* double backslashes for C compiler */
-#define SMB_IOCTL_FILENAME_NOSLASH "_._AFS_IOCTL_._"
+#define SMB_IOCTL_FILENAME        CM_IOCTL_FILENAME
+#define SMB_IOCTL_FILENAME_NOSLASH CM_IOCTL_FILENAME_NOSLASH
 
 /* max parms for ioctl, in either direction */
-#define SMB_IOCTL_MAXDATA      8192*2
+#define SMB_IOCTL_MAXDATA         CM_IOCTL_MAXDATA
+#define SMB_IOCTL_MAXPROCS         CM_IOCTL_MAXPROCS
+
+struct smb_fid;
+struct smb_user;
+struct smb_vc;
+
+/* ioctl parameter, while being assembled and/or processed */
+typedef struct smb_ioctl {
+    /* fid pointer */
+    struct smb_fid *fidp;
+
+    /* uid pointer */
+    struct smb_user *uidp;
+
+    /* pathname associated with the Tree ID */
+    char *tidPathp;
 
-#define SMB_IOCTL_MAXPROCS     64                      /* max # of calls */
+    /* prefix for subst drives */
+    cm_space_t *prefix;
+
+    cm_ioctl_t  ioctl;
+} smb_ioctl_t;
 
 /* procedure implementing an ioctl */
 typedef long (smb_ioctlProc_t)(smb_ioctl_t *, struct cm_user *userp);
 
 extern void smb_InitIoctl(void);
 
-extern void smb_SetupIoctlFid(smb_fid_t *fidp, cm_space_t *prefix);
+extern void smb_SetupIoctlFid(struct smb_fid *fidp, cm_space_t *prefix);
+
+extern afs_int32 smb_IoctlRead(struct smb_fid *fidp, struct smb_vc *vcp, struct smb_packet *inp, struct smb_packet *outp);
+
+extern afs_int32 smb_IoctlWrite(struct smb_fid *fidp, struct smb_vc *vcp, struct smb_packet *inp, struct smb_packet *outp);
+
+extern afs_int32 smb_IoctlV3Write(struct smb_fid *fidp, struct smb_vc *vcp, struct smb_packet *inp, struct smb_packet *outp);
+
+extern afs_int32 smb_IoctlV3Read(struct smb_fid *fidp, struct smb_vc *vcp, struct smb_packet *inp, struct smb_packet *outp);
+
+extern afs_int32 smb_IoctlReadRaw(struct smb_fid *fidp, struct smb_vc *vcp, struct smb_packet *inp,
+       struct smb_packet *outp);
+
+extern long smb_IoctlPrepareRead(struct smb_fid *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32
+smb_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp, cm_scache_t **scpp, afs_uint32 flags);
+
+extern afs_int32
+smb_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp, cm_scache_t **scpp, char *leafp);
+
+extern afs_int32 
+smb_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp);
+
+extern afs_int32
+smb_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlGetFileCellName(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlSetACL(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlFlushAllVolumes(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlFlushVolume(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlFlushFile(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlSetVolumeStatus(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlGetVolumeStatus(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlGetFid(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlGetOwner(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlWhereIs(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlStatMountPoint(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlDeleteMountPoint(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlCheckServers(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlGag(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlCheckVolumes(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlSetCacheSize(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlGetCacheParms(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlGetCell(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlNewCell(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlSysName(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlGetCellStatus(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlSetCellStatus(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlSetSPrefs(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlGetSPrefs(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlStoreBehind(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlCreateMountPoint(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 cm_CleanFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
+
+extern afs_int32 cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
+
+extern afs_int32 cm_FlushVolume(cm_user_t *, cm_req_t *reqp, afs_uint32 cell, afs_uint32 volume);
+
+extern afs_int32 cm_FlushParent(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
+
+extern afs_int32 smb_IoctlTraceControl(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlSetToken(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlGetTokenIter(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlGetToken(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlDelToken(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlDelAllToken(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlSymlink(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlIslink(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlListlink(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlDeletelink(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlGetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlSetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlShutdown(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlFreemountAddCell(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlFreemountRemoveCell(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlMemoryDump(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
+extern afs_int32 smb_IoctlRxStatProcess(smb_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long smb_IoctlRead(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp);
+extern afs_int32 smb_IoctlRxStatPeer(smb_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long smb_IoctlWrite(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp);
+extern afs_int32 smb_IoctlUUIDControl(struct smb_ioctl * ioctlp, struct cm_user *userp);
 
-extern long smb_IoctlV3Write(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp);
+extern afs_int32 smb_IoctlPathAvailability(struct smb_ioctl * ioctlp, struct cm_user *userp);
 
-extern long smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp);
+extern afs_int32 smb_IoctlGetFileType(smb_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern long smb_IoctlReadRaw(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
-       smb_packet_t *outp);
+extern afs_int32 smb_IoctlVolStatTest(struct smb_ioctl *ioctlp, struct cm_user *userp);
 
-extern long smb_IoctlPrepareRead(smb_fid_t *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp);
+extern afs_int32 smb_IoctlUnicodeControl(struct smb_ioctl *ioctlp, struct cm_user * userp);
 
 #endif /*  __SMB_IOCTL_H_ENV__ */