windows-cm_ioctl_query_opts-20080115
authorJeffrey Altman <jaltman@secure-endpoints.com>
Wed, 16 Jan 2008 03:16:19 +0000 (03:16 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Wed, 16 Jan 2008 03:16:19 +0000 (03:16 +0000)
LICENSE MIT

The path ioctl operations have several issues:

(1) the specified path for "fs examine, whereis, whichcell, flush" and so
    always has the follow symlinks and mount points semantics.  This makes
    it impossible to determine what the FID of a symlink or mount point is.

(2) "fs examine" out is not the result of a single pioctl operation but is
    actually the combined output of half a dozen operations.  Path evaluation
    is an expensive operation.  It would be faster if the caller could
    evaluate the FID first and then perform all of the rest of the operations
    by specifying the FID instead of the path.

(3) fs output reports all objects as files.  By adding a GetFileType
    pioctl more informative output can be provided that indicates what
    type of object the path evaluates to.

(4) the Windows fs command includes a number of commands that do nothing
    but exist only because the Unix cache manager supports them.

This delta adds a new extendible data structure cm_ioctl_query_opts_t which
can be optionally specified with pioctls that do not already require
input data.  The first two fields of this structure are 'literal' and
'fid'.  The literal field is used to indicate whether the last component
of the path should be evaluated following symlinks and mount points.
The fid field permits a fid to be specified.

A new GetFileType pioctl has been added. The type of objects are now
output.

A new "-literal" option is available for "fs examine, flush, whereis, and
whichcell.

Unimplemented fs commands have been removed.

src/WINNT/afsd/afsd_init.c
src/WINNT/afsd/cm_ioctl.c
src/WINNT/afsd/cm_ioctl.h
src/WINNT/afsd/fs.c
src/WINNT/afsd/smb_iocons.h
src/WINNT/afsd/smb_ioctl.c

index 4d6c0de..735bc3d 100644 (file)
@@ -44,7 +44,6 @@ extern afs_int32 cryptall;
 extern int cm_enableServerLocks;
 extern int cm_followBackupPath;
 extern int cm_deleteReadOnly;
-extern afs_uint32 cm_pioctlFollowMountPoint;
 #ifdef USE_BPLUS
 extern afs_int32 cm_BPlusTrees;
 #endif
@@ -1150,14 +1149,6 @@ int afsd_InitCM(char **reasonP)
     } 
     afsi_log("CM FollowBackupPath is %u", cm_followBackupPath);
 
-    dummyLen = sizeof(DWORD);
-    code = RegQueryValueEx(parmKey, "PioctlFollowMountPoint", NULL, NULL,
-                           (BYTE *) &dwValue, &dummyLen);
-    if (code == ERROR_SUCCESS) {
-        cm_pioctlFollowMountPoint = (afs_uint32) dwValue;
-    } 
-    afsi_log("CM PioctlFollowMountPoint is %u", cm_pioctlFollowMountPoint);
-
     RegCloseKey (parmKey);
 
     cacheBlocks = ((afs_uint64)cacheSize * 1024) / blockSize;
index 53af6ba..993caa8 100644 (file)
@@ -53,8 +53,6 @@ extern char cm_NetbiosName[];
 
 extern void afsi_log(char *pattern, ...);
 
-afs_uint32 cm_pioctlFollowMountPoint = 0;
-
 void cm_InitIoctl(void)
 {
     lock_InitializeMutex(&cm_Afsdsbmt_Lock, "AFSDSBMT.INI Access Lock");
@@ -195,8 +193,10 @@ void TranslateExtendedChars(char *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)
+       cm_scache_t **scpp, afs_uint32 flags)
 {
     long code;
 #ifndef AFSIFS
@@ -205,7 +205,7 @@ long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
 #endif
     char * relativePath;
     char * lastComponent = NULL;
-    afs_uint32 follow = (cm_pioctlFollowMountPoint ? CM_FLAG_FOLLOW : CM_FLAG_NOMOUNTCHASE);
+    afs_uint32 follow = (flags & CM_PARSE_FLAG_LITERAL ? CM_FLAG_NOMOUNTCHASE : CM_FLAG_FOLLOW);
 
     relativePath = ioctlp->inDatap;
     /* setup the next data value for the caller to use */
@@ -389,12 +389,42 @@ long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
 
 void cm_SkipIoctlPath(smb_ioctl_t *ioctlp)
 {
-    long temp;
+    size_t temp;
         
-    temp = (long) strlen(ioctlp->inDatap) + 1;
+    temp = strlen(ioctlp->inDatap) + 1;
     ioctlp->inDatap += temp;
 }       
 
+/* 
+ * Must be called before cm_ParseIoctlPath or cm_SkipIoctlPath 
+ */
+static cm_ioctlQueryOptions_t * 
+cm_IoctlGetQueryOptions(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    afs_uint32 pathlen = strlen(ioctlp->inDatap) + 1;
+    char *p = ioctlp->inDatap + pathlen;
+    cm_ioctlQueryOptions_t * optionsp = NULL;
+
+    if (ioctlp->inCopied > p - ioctlp->inAllocp) {
+        optionsp = (cm_ioctlQueryOptions_t *)p;
+        if (optionsp->size < 12 /* minimum size of struct */)
+            optionsp = NULL;
+    }
+
+    return optionsp;
+}
+
+/* 
+ * Must be called after cm_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)
+{
+    cm_ioctlQueryOptions_t * optionsp = (cm_ioctlQueryOptions_t *)ioctlp->inDatap;
+    ioctlp->inDatap += optionsp->size;
+}
 
 /* format the specified path to look like "/afs/<cellname>/usr", by
  * adding "/afs" (if necessary) in front, changing any \'s to /'s, and
@@ -560,11 +590,24 @@ long cm_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
     int tlen;
     cm_req_t req;
     struct rx_connection * callp;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
 
     cm_InitReq(&req);
 
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
-    if (code) return code;
+    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_SkipIoctlPath(ioctlp);
+
+        code = cm_GetSCache(&optionsp->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
@@ -607,11 +650,23 @@ long cm_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp)
     cm_scache_t *scp;
     cm_cell_t *cellp;
     cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
 
     cm_InitReq(&req);
 
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
-    if (code) return code;
+    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_SkipIoctlPath(ioctlp);
+        code = cm_GetSCache(&optionsp->fid, &scp, userp, &req);
+    } else {
+        code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code) 
+        return code;
 
 #ifdef AFS_FREELANCE_CLIENT
     if ( cm_freelanceEnabled && 
@@ -652,7 +707,7 @@ long cm_IoctlSetACL(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
     cm_InitReq(&req);
 
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
+    code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, 0);
     if (code) return code;
        
 #ifdef AFS_FREELANCE_CLIENT
@@ -699,6 +754,8 @@ long cm_IoctlFlushAllVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
     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) {
@@ -723,12 +780,24 @@ long cm_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
     unsigned long volume;
     unsigned long cell;
     cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
 
     cm_InitReq(&req);
 
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
-    if (code) return code;
-        
+    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_SkipIoctlPath(ioctlp);
+        code = cm_GetSCache(&optionsp->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 = CM_ERROR_NOACCESS;
@@ -749,12 +818,24 @@ long cm_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
     long code;
     cm_scache_t *scp;
     cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
 
     cm_InitReq(&req);
 
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
-    if (code) return code;
-        
+    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_SkipIoctlPath(ioctlp);
+        code = cm_GetSCache(&optionsp->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 = CM_ERROR_NOACCESS;
@@ -786,7 +867,7 @@ long cm_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
     cm_InitReq(&req);
 
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
+    code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, 0);
     if (code) return code;
 
 #ifdef AFS_FREELANCE_CLIENT
@@ -884,11 +965,23 @@ long cm_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
     char *MOTD;
     cm_req_t req;
     struct rx_connection * callp;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
 
     cm_InitReq(&req);
 
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
-    if (code) return code;
+    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_SkipIoctlPath(ioctlp);
+        code = cm_GetSCache(&optionsp->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 ) {
@@ -947,13 +1040,20 @@ long cm_IoctlGetFid(struct smb_ioctl *ioctlp, struct cm_user *userp)
     register char *cp;
     cm_fid_t fid;
     cm_req_t req;
+    cm_ioctlQueryOptions_t * optionsp;
+    afs_uint32 flags = 0;
 
     cm_InitReq(&req);
 
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
+    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;
     fid.volume = scp->fid.volume;
     fid.vnode  = scp->fid.vnode;
     fid.unique = scp->fid.unique;
@@ -971,17 +1071,68 @@ long cm_IoctlGetFid(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return 0;
 }
 
+long cm_IoctlGetFileType(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    cm_scache_t *scp;
+    register long code;
+    register 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_SkipIoctlPath(ioctlp);
+        code = cm_GetSCache(&optionsp->fid, &scp, userp, &req);
+    } else {
+        code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    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);
+
+    /* return new size */
+    ioctlp->outDatap = cp;
+
+    return 0;
+}
+
 long cm_IoctlGetOwner(struct smb_ioctl *ioctlp, struct cm_user *userp)
 {
     cm_scache_t *scp;
     register long code;
     register char *cp;
     cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
 
     cm_InitReq(&req);
 
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
-    if (code) return code;
+    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_SkipIoctlPath(ioctlp);
+        code = cm_GetSCache(&optionsp->fid, &scp, userp, &req);
+    } else {
+        code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code) 
+        return code;
 
     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
     cp = ioctlp->outDatap;
@@ -1009,12 +1160,24 @@ long cm_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
     unsigned long volume;
     char *cp;
     cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
 
     cm_InitReq(&req);
 
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
-    if (code) return code;
-        
+    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_SkipIoctlPath(ioctlp);
+        code = cm_GetSCache(&optionsp->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);
@@ -1024,31 +1187,55 @@ long cm_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
     if (!cellp)
        return CM_ERROR_NOSUCHCELL;
 
-    code = cm_GetVolumeByID(cellp, volume, userp, &req, CM_GETVOL_FLAG_CREATE, &tvp);
-    if (code) 
-        return code;
+#ifdef AFS_FREELANCE_CLIENT
+    if ( cellp->cellID == AFS_FAKE_ROOT_CELL_ID) {
+        struct in_addr addr;
+
+        addr.s_net = 127;
+        addr.s_host = 0;
+        addr.s_lh = 0;
+        addr.s_impno = 1;
+
+        cp = ioctlp->outDatap;
+        
+        memcpy(cp, (char *)&addr, sizeof(addr));
+        cp += sizeof(addr);
+
+        /* still room for terminating NULL, add it on */
+        addr.s_addr = 0;
+        memcpy(cp, (char *)&addr, sizeof(addr));
+        cp += sizeof(addr);
+
+        ioctlp->outDatap = cp;
+    } else 
+#endif
+    {
+        code = cm_GetVolumeByID(cellp, volume, userp, &req, CM_GETVOL_FLAG_CREATE, &tvp);
+        if (code) 
+            return code;
        
-    cp = ioctlp->outDatap;
+        cp = ioctlp->outDatap;
         
-    lock_ObtainMutex(&tvp->mx);
-    tsrpp = cm_GetVolServers(tvp, volume);
-    lock_ObtainRead(&cm_serverLock);
-    for (current = *tsrpp; current; current = current->next) {
-        tsp = current->server;
-        memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
-        cp += sizeof(long);
-    }
-    lock_ReleaseRead(&cm_serverLock);
-    cm_FreeServerList(tsrpp, 0);
-    lock_ReleaseMutex(&tvp->mx);
+        lock_ObtainMutex(&tvp->mx);
+        tsrpp = cm_GetVolServers(tvp, volume);
+        lock_ObtainRead(&cm_serverLock);
+        for (current = *tsrpp; current; current = current->next) {
+            tsp = current->server;
+            memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
+            cp += sizeof(long);
+        }
+        lock_ReleaseRead(&cm_serverLock);
+        cm_FreeServerList(tsrpp, 0);
+        lock_ReleaseMutex(&tvp->mx);
 
-    /* still room for terminating NULL, add it on */
-    volume = 0;        /* reuse vbl */
-    memcpy(cp, (char *)&volume, sizeof(long));
-    cp += sizeof(long);
+        /* still room for terminating NULL, add it on */
+        volume = 0;    /* reuse vbl */
+        memcpy(cp, (char *)&volume, sizeof(long));
+        cp += sizeof(long);
 
-    ioctlp->outDatap = cp;
-    cm_PutVolume(tvp);
+        ioctlp->outDatap = cp;
+        cm_PutVolume(tvp);
+    }
     return 0;
 }       
 
@@ -1062,7 +1249,7 @@ long cm_IoctlStatMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
     cm_InitReq(&req);
 
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
+    code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
     if (code) return code;
 
     cp = ioctlp->inDatap;
@@ -1103,7 +1290,7 @@ long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
     cm_InitReq(&req);
 
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
+    code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
     if (code) return code;
 
     cp = ioctlp->inDatap;
@@ -1869,7 +2056,7 @@ long cm_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
     cm_InitReq(&req);
 
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
+    code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
     if (code) return code;
 
     cp = ioctlp->inDatap;
@@ -1927,7 +2114,7 @@ long cm_IoctlIslink(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
     cm_InitReq(&req);
 
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
+    code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
     if (code) return code;
 
     cp = ioctlp->inDatap;
@@ -1956,7 +2143,7 @@ long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
     cm_InitReq(&req);
 
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
+    code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
     if (code) return code;
 
     cp = ioctlp->inDatap;
@@ -2886,10 +3073,21 @@ long cm_IoctlPathAvailability(struct smb_ioctl *ioctlp, struct cm_user *userp)
     cm_vol_state_t *statep;
     afs_uint32 volume;
     cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
 
     cm_InitReq(&req);
 
-    code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
+    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_SkipIoctlPath(ioctlp);
+        code = cm_GetSCache(&optionsp->fid, &scp, userp, &req);
+    } else {
+        code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
     if (code) 
         return code;
         
index 8f9890e..be3715f 100644 (file)
 #ifndef __CM_IOCTL_INTERFACES_ONLY__
 #include "smb.h"
 #include "cm_user.h"
+#else
+typedef struct cm_fid {
+        unsigned long cell;
+        unsigned long volume;
+        unsigned long vnode;
+        unsigned long unique;
+} cm_fid_t;
 #endif /* __CM_IOCTL_INTERFACES_ONLY__ */
 
 /* the following four structures are used for fs get/set serverprefs command*/
@@ -45,6 +52,47 @@ typedef struct cm_cacheParms {
         afs_uint64 parms[CM_IOCTLCACHEPARMS];
 } cm_cacheParms_t;
 
+/* 
+ * The cm_IoctlQueryOptions structure is designed to be extendible.
+ * None of the fields are required but when specified 
+ * by the client and understood by the server will be 
+ * used to more precisely specify the desired data.
+ *
+ * size must be set to the size of the structure 
+ * sent by the client including any variable length
+ * data appended to the end of the static structure.
+ *
+ * field_flags are used to determine which fields have
+ * been filled in and should be used.
+ *
+ * variable length data can be specified with fields
+ * that include offsets to data appended to the 
+ * structure.
+ *
+ * when adding new fields you must:
+ *  - add the field
+ *  - define a CM_IOCTL_QOPTS_FIELD_xxx bit flag
+ *  - define a CM_IOCTL_QOPTS_HAVE_xxx macro
+ *
+ * It is critical that flags be consistent across all
+ * implementations of the pioctl interface for a given
+ * platform.  This should be considered a public 
+ * interface used by third party application developers.
+ */
+
+typedef struct cm_IoctlQueryOptions {
+    afs_uint32  size; 
+    afs_uint32  field_flags;
+    afs_uint32  literal;
+    cm_fid_t    fid;
+} cm_ioctlQueryOptions_t;
+
+/* field flags -  */
+#define CM_IOCTL_QOPTS_FIELD_LITERAL 1
+#define CM_IOCTL_QOPTS_FIELD_FID     2
+
+#define CM_IOCTL_QOPTS_HAVE_LITERAL(p) (p->size >= 12 && (p->field_flags & CM_IOCTL_QOPTS_FIELD_LITERAL))
+#define CM_IOCTL_QOPTS_HAVE_FID(p)     (p->size >= 28 && (p->field_flags & CM_IOCTL_QOPTS_FIELD_FID))
 
 #define MAXNUMSYSNAMES    16      /* max that current constants allow */
 #define   MAXSYSNAME      128     /* max sysname (i.e. @sys) size */
@@ -171,6 +219,8 @@ extern long cm_IoctlUUIDControl(struct smb_ioctl * ioctlp, struct cm_user *userp
 
 extern long cm_IoctlPathAvailability(struct smb_ioctl * ioctlp, struct cm_user *userp);
 
+extern long cm_IoctlGetFileType(smb_ioctl_t *ioctlp, cm_user_t *userp);
+
 extern long cm_IoctlVolStatTest(struct smb_ioctl *ioctlp, struct cm_user *userp);
 
 #endif /* __CM_IOCTL_INTERFACES_ONLY__ */
index 205d607..22438f3 100644 (file)
@@ -1374,11 +1374,23 @@ FlushCmd(struct cmd_syndesc *as, void *arock)
     afs_int32 code;
     struct ViceIoctl blob;
     struct cmd_item *ti;
-
     int error = 0;
+    int literal = 0;
+    cm_ioctlQueryOptions_t options;
 
+    if (as->parms[1].items)
+        literal = 1;
+    
     for(ti=as->parms[0].items; ti; ti=ti->next) {
-       blob.in_size = blob.out_size = 0;
+        /* once per file */
+        memset(&options, 0, sizeof(options));
+        options.size = sizeof(options);
+        options.field_flags |= CM_IOCTL_QOPTS_FIELD_LITERAL;
+        options.literal = literal;
+       blob.in_size = options.size;    /* no variable length data */
+        blob.in = &options;
+
+       blob.out_size = 0;
        code = pioctl(ti->data, VIOCFLUSH, &blob, 0);
        if (code) {
            if (errno == EMFILE) {
@@ -1470,16 +1482,31 @@ SetVolCmd(struct cmd_syndesc *as, void *arock) {
     return error;
 }
 
-#ifndef WIN32
-/* 
- * Why is VenusFid declared in the kernel-only section of afs.h, 
- * if it's the exported interface of the (UNIX) cache manager?
- */
-struct VenusFid {
-    afs_int32 Cell;
-    AFSFid Fid;
-};
-#endif /* WIN32 */
+/* values match cache manager File Types */
+static char *
+filetypestr(afs_uint32 type)
+{
+    char * s = "Object";
+
+    switch (type) {
+    case 1:     /* file */
+        s = "File";
+        break;
+    case 2:
+        s = "Directory";
+        break;
+    case 3:
+        s = "Symlink";
+        break;
+    case 4:
+        s = "Mountpoint";
+        break;
+    case 5:
+        s = "DfsLink";
+        break;
+    }
+    return s;
+}
 
 static int 
 ExamineCmd(struct cmd_syndesc *as, void *arock)
@@ -1490,31 +1517,54 @@ ExamineCmd(struct cmd_syndesc *as, void *arock)
     struct VolumeStatus *status;
     char *name, *offmsg, *motd;
     int error = 0;
-    
+    int literal = 0;
+    cm_ioctlQueryOptions_t options;
+
+    if (as->parms[1].items)
+        literal = 1;
+
     SetDotDefault(&as->parms[0].items);
     for(ti=as->parms[0].items; ti; ti=ti->next) {
         cm_fid_t fid;
+        afs_uint32 filetype;
        afs_uint32 owner[2];
        char cell[MAXCELLCHARS];
 
-       code = GetCell(ti->data, cell);
-       if (code) {
-           Die(errno, ti->data);
-           error = 1;
-           continue;
-       }
-
-       /* once per file */
-       blob.in_size = 0;
+        /* once per file */
+        memset(&fid, 0, sizeof(fid));
+        memset(&options, 0, sizeof(options));
+        filetype = 0;
+        options.size = sizeof(options);
+        options.field_flags |= CM_IOCTL_QOPTS_FIELD_LITERAL;
+        options.literal = literal;
+       blob.in_size = options.size;    /* no variable length data */
+        blob.in = &options;
 
         blob.out_size = sizeof(cm_fid_t);
         blob.out = (char *) &fid;
         if (0 == pioctl(ti->data, VIOCGETFID, &blob, 1)) {
-            printf("File %s (%u.%u.%u) contained in cell %s\n",
-                    ti->data, fid.volume, fid.vnode, fid.unique,
-                    cell);
+            options.field_flags |= CM_IOCTL_QOPTS_FIELD_FID;
+            options.fid = fid;
+        } else {
+           Die(errno, ti->data);
+           error = 1;
+           continue;
         }
 
+        blob.out_size = sizeof(filetype);
+        blob.out = &filetype;
+
+        code = pioctl(ti->data, VIOC_GETFILETYPE, &blob, 1);
+
+        blob.out_size = MAXCELLCHARS;
+        blob.out = cell;
+
+        code = pioctl(ti->data, VIOC_FILE_CELL_NAME, &blob, 1);
+        printf("%s %s (%u.%u.%u) contained in cell %s\n",
+                filetypestr(filetype),
+                ti->data, fid.volume, fid.vnode, fid.unique,
+                code ? "unknown-cell" : cell);
+
        blob.out_size = 2 * sizeof(afs_uint32);
         blob.out = (char *) &owner;
        if (0 == pioctl(ti->data, VIOCGETOWNER, &blob, 1)) {
@@ -1606,12 +1656,44 @@ WhereIsCmd(struct cmd_syndesc *as, void *arock)
     afs_int32 *hosts;
     char *tp;
     int error = 0;
+    int literal = 0;
+    cm_ioctlQueryOptions_t options;
+
+    if (as->parms[1].items)
+        literal = 1;
     
     SetDotDefault(&as->parms[0].items);
     for(ti=as->parms[0].items; ti; ti=ti->next) {
-       /* once per file */
-       blob.out_size = MAXSIZE;
-       blob.in_size = 0;
+        cm_fid_t fid;
+        afs_uint32 filetype;
+
+        /* once per file */
+        memset(&fid, 0, sizeof(fid));
+        memset(&options, 0, sizeof(options));
+        filetype = 0;
+        options.size = sizeof(options);
+        options.field_flags |= CM_IOCTL_QOPTS_FIELD_LITERAL;
+        options.literal = literal;
+       blob.in_size = options.size;    /* no variable length data */
+        blob.in = &options;
+        
+        blob.out_size = sizeof(cm_fid_t);
+        blob.out = (char *) &fid;
+        if (0 == pioctl(ti->data, VIOCGETFID, &blob, 1)) {
+            options.field_flags |= CM_IOCTL_QOPTS_FIELD_FID;
+            options.fid = fid;
+        } else {
+           Die(errno, ti->data);
+           error = 1;
+           continue;
+        }
+
+        blob.out_size = sizeof(filetype);
+        blob.out = &filetype;
+
+        code = pioctl(ti->data, VIOC_GETFILETYPE, &blob, 1);
+
+        blob.out_size = MAXSIZE;
        blob.out = space;
        memset(space, 0, sizeof(space));
        code = pioctl(ti->data, VIOCWHEREIS, &blob, 1);
@@ -1621,7 +1703,9 @@ WhereIsCmd(struct cmd_syndesc *as, void *arock)
            continue;
        }
        hosts = (afs_int32 *) space;
-       printf("File %s is on host%s ", ti->data, 
+       printf("%s %s is on host%s ", 
+                filetypestr(filetype),
+                ti->data,
                 (hosts[0] && !hosts[1]) ? "": "s");
        for(j=0; j<MAXHOSTS; j++) {
            if (hosts[j] == 0) 
@@ -2575,12 +2659,50 @@ WhichCellCmd(struct cmd_syndesc *as, void *arock)
 {
     afs_int32 code;
     struct cmd_item *ti;
+    struct ViceIoctl blob;
     int error = 0;
-    char cell[MAXCELLCHARS]="";
+    int literal = 0;
+    cm_ioctlQueryOptions_t options;
+
+    if (as->parms[1].items)
+        literal = 1;
     
     SetDotDefault(&as->parms[0].items);
     for(ti=as->parms[0].items; ti; ti=ti->next) {
-        code = GetCell(ti->data, cell);
+        cm_fid_t fid;
+        afs_uint32 filetype;
+       char cell[MAXCELLCHARS];
+
+        /* once per file */
+        memset(&fid, 0, sizeof(fid));
+        memset(&options, 0, sizeof(options));
+        filetype = 0;
+        options.size = sizeof(options);
+        options.field_flags |= CM_IOCTL_QOPTS_FIELD_LITERAL;
+        options.literal = literal;
+       blob.in_size = options.size;    /* no variable length data */
+        blob.in = &options;
+
+        blob.out_size = sizeof(cm_fid_t);
+        blob.out = (char *) &fid;
+        if (0 == pioctl(ti->data, VIOCGETFID, &blob, 1)) {
+            options.field_flags |= CM_IOCTL_QOPTS_FIELD_FID;
+            options.fid = fid;
+        } else {
+           Die(errno, ti->data);
+           error = 1;
+           continue;
+        }
+
+        blob.out_size = sizeof(filetype);
+        blob.out = &filetype;
+
+        code = pioctl(ti->data, VIOC_GETFILETYPE, &blob, 1);
+
+        blob.out_size = MAXCELLCHARS;
+        blob.out = cell;
+
+        code = pioctl(ti->data, VIOC_FILE_CELL_NAME, &blob, 1);
        if (code) {
            if (errno == ENOENT)
                fprintf(stderr,"%s: no such cell as '%s'\n", pn, ti->data);
@@ -2589,7 +2711,9 @@ WhichCellCmd(struct cmd_syndesc *as, void *arock)
            error = 1;
            continue;
        }
-        printf("File %s lives in cell '%s'\n", ti->data, cell);
+        printf("%s %s lives in cell '%s'\n",
+                filetypestr(filetype),
+                ti->data, cell);
     }
     return error;
 }
@@ -2625,6 +2749,7 @@ PrimaryCellCmd(struct cmd_syndesc *as, void *arock)
 }
 */
 
+#ifndef AFS_NT40_ENV
 static int
 MonitorCmd(struct cmd_syndesc *as, void *arock)
 {
@@ -2684,6 +2809,7 @@ MonitorCmd(struct cmd_syndesc *as, void *arock)
     }
     return 0;
 }
+#endif /* AFS_NT40_ENV */
 
 static int
 SysNameCmd(struct cmd_syndesc *as, void *arock)
@@ -2755,6 +2881,7 @@ SysNameCmd(struct cmd_syndesc *as, void *arock)
     return 0;
 }
 
+#ifndef AFS_NT40_ENV
 static char *exported_types[] = {"null", "nfs", ""};
 static int ExportAfsCmd(struct cmd_syndesc *as, void *arock)
 {
@@ -2856,7 +2983,7 @@ static int ExportAfsCmd(struct cmd_syndesc *as, void *arock)
     }
     return 0;
 }
-
+#endif
 
 static int
 GetCellCmd(struct cmd_syndesc *as, void *arock)
@@ -3006,7 +3133,7 @@ VLDBInit(int noAuthFlag, struct afsconf_cell *info)
 {
     afs_int32 code;
 
-    code = ugen_ClientInit(noAuthFlag, AFSDIR_CLIENT_ETC_DIRPATH, 
+    code = ugen_ClientInit(noAuthFlag, (char *)AFSDIR_CLIENT_ETC_DIRPATH, 
                           info->name, 0, &uclient, 
                            NULL, pn, rxkad_clear,
                            VLDB_MAXSERVERS, AFSCONF_VLDBSERVICE, 50,
@@ -4486,6 +4613,7 @@ main(int argc, char **argv)
 
     ts = cmd_CreateSyntax("flush", FlushCmd, NULL, "flush file from cache");
     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
+    cmd_AddParm(ts, "-literal", CMD_FLAG, CMD_OPTIONAL, "literal evaluation of mountpoints and symlinks");
     
 #ifndef WIN32
     ts = cmd_CreateSyntax("flushmount", FlushMountCmd, NULL,
@@ -4508,6 +4636,7 @@ main(int argc, char **argv)
 
     ts = cmd_CreateSyntax("examine", ExamineCmd, NULL, "display file/volume status");
     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
+    cmd_AddParm(ts, "-literal", CMD_FLAG, CMD_OPTIONAL, "literal evaluation of mountpoints and symlinks");
     cmd_CreateAlias(ts, "lv");
     cmd_CreateAlias(ts, "listvol");
     
@@ -4597,9 +4726,11 @@ main(int argc, char **argv)
 
     ts = cmd_CreateSyntax("whichcell", WhichCellCmd, NULL, "list file's cell");
     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
+    cmd_AddParm(ts, "-literal", CMD_FLAG, CMD_OPTIONAL, "literal evaluation of mountpoints and symlinks");
 
     ts = cmd_CreateSyntax("whereis", WhereIsCmd, NULL, "list file's location");
     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
+    cmd_AddParm(ts, "-literal", CMD_FLAG, CMD_OPTIONAL, "literal evaluation of mountpoints and symlinks");
 
     ts = cmd_CreateSyntax("wscell", WSCellCmd, NULL, "list workstation's cell");
     
@@ -4607,11 +4738,12 @@ main(int argc, char **argv)
      ts = cmd_CreateSyntax("primarycell", PrimaryCellCmd, 0, "obsolete (listed primary cell)");
      */
     
+#ifndef AFS_NT40_ENV
     ts = cmd_CreateSyntax("monitor", MonitorCmd, NULL, "set cache monitor host address");
     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "host name or 'off'");
     cmd_CreateAlias(ts, "mariner");
-    
-   
+#endif
+
     ts = cmd_CreateSyntax("getcellstatus", GetCellCmd, NULL, "get cell status");
     cmd_AddParm(ts, "-cell", CMD_LIST, 0, "cell name");
     
@@ -4628,13 +4760,14 @@ main(int argc, char **argv)
     ts = cmd_CreateSyntax("sysname", SysNameCmd, NULL, "get/set sysname (i.e. @sys) value");
     cmd_AddParm(ts, "-newsys", CMD_LIST, CMD_OPTIONAL, "new sysname");
 
+#ifndef AFS_NT40_ENV
     ts = cmd_CreateSyntax("exportafs", ExportAfsCmd, NULL, "enable/disable translators to AFS");
     cmd_AddParm(ts, "-type", CMD_SINGLE, 0, "exporter name");
     cmd_AddParm(ts, "-start", CMD_SINGLE, CMD_OPTIONAL, "start/stop translator ('on' or 'off')");
     cmd_AddParm(ts, "-convert", CMD_SINGLE, CMD_OPTIONAL, "convert from afs to unix mode ('on or 'off')");
     cmd_AddParm(ts, "-uidcheck", CMD_SINGLE, CMD_OPTIONAL, "run on strict 'uid check' mode ('on' or 'off')");
     cmd_AddParm(ts, "-submounts", CMD_SINGLE, CMD_OPTIONAL, "allow nfs mounts to subdirs of /afs/.. ('on' or 'off')");
-
+#endif
 
     ts = cmd_CreateSyntax("storebehind", StoreBehindCmd, NULL, 
                          "store to server after file close");
index 83b2b57..bf23849 100644 (file)
@@ -93,6 +93,7 @@ struct sbstruct {
 #define VIOC_RXSTAT_PEER                0x2f
 #define VIOC_UUIDCTL                    0x30
 #define VIOC_PATH_AVAILABILITY          0x31
+#define VIOC_GETFILETYPE                0x32
 
 #define VIOC_VOLSTAT_TEST               0x3F
 /* Not to exceed SMB_IOCTL_MAXPROCS from smb_ioctl.h */
index a66cfa7..7f3715e 100644 (file)
@@ -80,6 +80,7 @@ void smb_InitIoctl(void)
         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;
 }