afsio: switch BreakUpPath to strdup
[openafs.git] / src / venus / afsio.c
index f0690c6..9e3b1e5 100644 (file)
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+/*
+ * Revised in 2010 by Chaz Chandler to enhance clientless operations.
+ * Now utilizes libafscp by Chaskiel Grundman.
+ * Work funded in part by Sine Nomine Associates (http://www.sinenomine.net/)
+ */
 
 #include <afsconfig.h>
 #include <afs/param.h>
+#include <afs/stds.h>
 
 #include <roken.h>
 
-#include <afs/stds.h>
-
-#include <stdio.h>
-#include <setjmp.h>
-#include <sys/types.h>
-#include <string.h>
-#include <ctype.h>
 #ifdef AFS_NT40_ENV
 #include <windows.h>
-#include <winsock2.h>
 #define _CRT_RAND_S
-#include <stdlib.h>
-#include <process.h>
-#include <fcntl.h>
-#include <io.h>
 #include <afs/smb_iocons.h>
 #include <afs/afsd.h>
 #include <afs/cm_ioctl.h>
 #include <afs/pioctl_nt.h>
 #include <WINNT/syscfg.h>
 #else
-#include <sys/param.h>
-#include <sys/file.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <string.h>
-#include <fcntl.h>
-#include <pwd.h>
-#include <afs/venus.h>
-#include <sys/time.h>
-#include <netdb.h>
 #include <afs/afsint.h>
 #define FSINT_COMMON_XG 1
 #endif
-#include <sys/stat.h>
-#include <errno.h>
-#include <signal.h>
-#include <afs/vice.h>
+
+#include <afs/opr.h>
 #include <afs/cmd.h>
 #include <afs/auth.h>
-#include <afs/cellconfig.h>
-#include <afs/afsutil.h>
-#include <rx/rx.h>
-#include <rx/xdr.h>
-#include <afs/afs_consts.h>
-#include <afs/afscbint.h>
-#include <afs/vldbint.h>
 #include <afs/vlserver.h>
-#include <afs/volser.h>
-#include <afs/ptint.h>
-#include <afs/dir.h>
-#include <afs/nfs.h>
 #include <afs/ihandle.h>
-#include <afs/vnode.h>
 #include <afs/com_err.h>
-#ifdef HAVE_DIRENT_H
-#include <dirent.h>
-#endif
+#include <afs/afscp.h>
+
 #ifdef HAVE_DIRECT_H
 #include <direct.h>
 #endif
-#ifdef AFS_DARWIN_ENV
-#include <sys/malloc.h>
-#else
-#include <malloc.h>
-#endif
-#include <afs/errors.h>
-#include <afs/sys_prototypes.h>
-#include <rx/rx_prototypes.h>
 #include <hcrypto/md5.h>
-
-#ifdef O_LARGEFILE
-#define afs_stat        stat64
-#define afs_fstat       fstat64
-#define afs_open        open64
-#else /* !O_LARGEFILE */
-#define afs_stat        stat
-#define afs_fstat       fstat
-#define afs_open        open
-#endif /* !O_LARGEFILE */
 #ifdef AFS_PTHREAD_ENV
-#include <assert.h>
 pthread_key_t uclient_key;
 #endif
 
-int readFile(struct cmd_syndesc *as, void *);
-int writeFile(struct cmd_syndesc *as, void *);
-struct rx_connection *FindRXConnection(afs_uint32 host, u_short port, u_short service, struct rx_securityClass *securityObject, int serviceSecurityIndex);
-struct cellLookup * FindCell(char *cellName);
-
-char pnp[255];
-int rxInitDone = 0;
+static int lockFile(struct cmd_syndesc *, void *);
+static int readFile(struct cmd_syndesc *, void *);
+static int writeFile(struct cmd_syndesc *, void *);
+static void printDatarate(void);
+static void summarizeDatarate(struct timeval *, const char *);
+static int CmdProlog(struct cmd_syndesc *, char **, char **,
+                     char **, char **);
+static int ScanFid(char *, struct AFSFid *);
+static afs_int32 GetVenusFidByFid(char *, char *, int, struct afscp_venusfid **);
+static afs_int32 GetVenusFidByPath(char *, char *, struct afscp_venusfid **);
+static int BreakUpPath(char *, char **, char **);
+
+static char pnp[AFSPATHMAX];   /* filename of this program when called */
 static int verbose = 0;                /* Set if -verbose option given */
-static int CBServiceNeeded = 0;
+static int clear = 0;          /* Set if -clear option given,
+                                  Unset if -crypt given; default is -crypt */
+static int cellGiven = 0;      /* Set if -cell option given */
+static int force = 0;          /* Set if -force option given */
+static int readlock = 0;       /* Set if -readlock option given */
+static int waittime = 0;       /* Set if -waittime option given */
+static int useFid = 0;         /* Set if fidwrite/fidread/fidappend invoked */
+static int append = 0;         /* Set if append/fidappend invoked */
 static struct timeval starttime, opentime, readtime, writetime;
-afs_uint64 xfered=0, oldxfered=0;
+static afs_uint64 xfered = 0;
 static struct timeval now;
-struct timezone Timezone;
-static float seconds, datarate, oldseconds;
-extern int rxInitDone;
 #ifdef AFS_NT40_ENV
-static afs_int32 rx_mtu = -1;
+static int Timezone;            /* Roken gettimeofday ignores the timezone */
+#else
+static struct timezone Timezone;
 #endif
-afs_uint64 transid = 0;
-afs_uint32 expires = 0;
-afs_uint32 server_List[MAXHOSTSPERCELL];
-char tmpstr[1024];
-char tmpstr2[1024];
-static struct ubik_client *uclient;
+
 #define BUFFLEN 65536
-#define WRITEBUFFLEN 1024*1024*64
+#define WRITEBUFLEN (BUFFLEN * 1024)
+#define MEGABYTE_F 1048576.0f
 
-afsUUID uuid;
-MD5_CTX md5;
-int md5sum = 0;
+static MD5_CTX md5;
+static int md5sum = 0;         /* Set if -md5 option given */
 
 struct wbuf {
     struct wbuf *next;
@@ -157,812 +111,650 @@ struct wbuf {
     char buf[BUFFLEN];
 };
 
-struct connectionLookup {
-    afs_uint32 host;
-    u_short port;
-    struct rx_connection *conn;
-};
-
-struct cellLookup {
-    struct cellLookup *next;
-    struct afsconf_cell info;
-    struct rx_securityClass *sc;
-    afs_int32 scIndex;
-};
+/*!
+ *  returns difference in seconds between two times
+ *
+ *  \param[in] from    start time
+ *  \param[in] to      end time
+ *
+ *  \post returns "to" minus "from" in seconds
+ *
+ */
+static_inline float
+time_elapsed(struct timeval *from, struct timeval *to)
+{
+    return (float)(to->tv_sec + (to->tv_usec * 0.000001) - from->tv_sec -
+                  (from->tv_usec * 0.000001));
+} /* time_elapsed */
 
-struct dirLookup {
-    struct dirLookup *next;
-    struct dirLookup *prev;
-    afs_int32 host;
-    struct cellLookup *cell;
-    AFSFid fid;
-    char name[VL_MAXNAMELEN];
-};
+/*!
+ * prints current average data transfer rate at no less than 30-second intervals
+ */
+static void
+printDatarate(void)
+{
+    static float oldseconds = 0.0;
+    static afs_uint64 oldxfered = 0;
+    float seconds;
+
+    gettimeofday(&now, &Timezone);
+    seconds = time_elapsed(&opentime, &now);
+    if ((seconds - oldseconds) > 30) {
+       fprintf(stderr, "%llu MB transferred, present data rate = %.3f MB/sec.\n", xfered >> 20,        /* total bytes transferred, in MB */
+               (xfered - oldxfered) / (seconds - oldseconds) / MEGABYTE_F);
+       oldxfered = xfered;
+       oldseconds = seconds;
+    }
+} /* printDatarate */
 
-struct cellLookup *Cells = 0;
-struct dirLookup  *Dirs = 0;
-char cellFname[256];
+/*!
+ * prints overall average data transfer rate and elapsed time
+ *
+ * \param[in]  tvp             current time (to compare with file open time)
+ * \param[in]  xfer_type       string identify transfer type ("read" or "write")
+ */
+static void
+summarizeDatarate(struct timeval *tvp, const char *xfer_type)
+{
+    float seconds = time_elapsed(&opentime, tvp);
 
-#define MAX_HOSTS 256
-static struct connectionLookup ConnLookup[MAX_HOSTS];
-static int ConnLookupInitialized = 0;
+    fprintf(stderr, "Transfer of %llu bytes took %.3f sec.\n",
+           xfered, seconds);
+    fprintf(stderr, "Total data rate = %.03f MB/sec. for %s\n",
+           xfered / seconds / MEGABYTE_F, xfer_type);
+} /* summarizeDatarate */
 
-struct FsCmdInputs PioctlInputs;
-struct FsCmdOutputs PioctlOutputs;
+/*!
+ * prints final MD5 sum of all file data transferred
+ *
+ * \param[in]  fname   file name or FID
+ */
+static void
+summarizeMD5(char *fname)
+{
+    afs_uint32 md5int[4];
+    char *p;
+
+    MD5_Final((char *) &md5int[0], &md5);
+    p = fname + strlen(fname);
+    while (p > fname) {
+       if (*(--p) == '/') {
+           ++p;
+           break;
+       }
+    }
+    fprintf(stderr, "%08x%08x%08x%08x  %s\n", htonl(md5int[0]),
+           htonl(md5int[1]), htonl(md5int[2]), htonl(md5int[3]), p);
+} /* summarizeMD5 */
 
-void
-printDatarate(void)
+#ifdef AFS_NT40_ENV
+static void
+ConvertAFSPath(char **fnp)
 {
-    seconds = (float)(now.tv_sec + now.tv_usec *.000001
-       -opentime.tv_sec - opentime.tv_usec *.000001);
-    if ((seconds - oldseconds) > 30.) {
-       afs_int64 tmp;
-       tmp = xfered - oldxfered;
-        datarate = ((afs_uint32) (tmp >> 20)) / (seconds - oldseconds);
-        fprintf(stderr,"%llu MB transferred, present date rate = %.03f MB/sec.\n",
-               xfered >> 20, datarate);
-       oldxfered = xfered;
-       oldseconds = seconds;
+    char *p;
+
+    for (p = *fnp; *p; p++) {
+        if (*p == '\\')
+           *p = '/';
     }
+
+    p = *fnp;
+    if (p[0] == '/' && p[1] == '/')
+        *fnp = p+1;
 }
+#endif /* AFS_NT40_ENV */
 
-void
-SetCellFname(char *name)
+/*!
+ * parses all command-line arguments
+ *
+ * \param[in]  as      arguments list
+ * \param[out] cellp   cell name
+ * \param[out] realmp  realm name
+ * \param[out] fnp     filename (either fid or path)
+ * \param[out] slp     "synthesized" (made up) data given
+ *
+ * \post returns 0 on success or -1 on error
+ *
+ */
+static int
+CmdProlog(struct cmd_syndesc *as, char **cellp, char **realmp,
+          char **fnp, char **slp)
 {
-    struct afsconf_dir *tdir;
-
-    strcpy((char *) &cellFname,"/afs/");
-    if (name)
-       strcat((char *) &cellFname, name);
-    else {
-       tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
-       afsconf_GetLocalCell(tdir, &cellFname[5], MAXCELLCHARS);
+    int i;
+    struct cmd_parmdesc *pdp;
+
+    if (as == NULL) {
+       afs_com_err(pnp, EINVAL, "(syndesc is null)");
+       return -1;
     }
-}
 
-afs_int32
-main (int argc, char **argv)
+    /* determine which command was requested */
+    if (strncmp(as->name, "fid", 3) == 0) /* fidread/fidwrite/fidappend */
+       useFid = 1;
+    if ( (strcmp(as->name, "append") == 0) ||
+         (strcmp(as->name, "fidappend") == 0) )
+       append = 1;             /* global */
+
+    /* attempts to ensure loop is bounded: */
+    for (pdp = as->parms, i = 0; pdp && (i < as->nParms); i++, pdp++) {
+       if (pdp->items != NULL) {
+           if (strcmp(pdp->name, "-verbose") == 0)
+               verbose = 1;
+           if (strcmp(pdp->name, "-clear") == 0)
+               clear = 1;
+           if (strcmp(pdp->name, "-crypt") == 0)
+               clear = 0;
+            else if (strcmp(pdp->name, "-md5") == 0)
+               md5sum = 1;     /* global */
+            else if (strcmp(pdp->name, "-cell") == 0) {
+               cellGiven = 1;  /* global */
+               *cellp = pdp->items->data;
+            } else if ( strcmp(pdp->name, "-file") == 0) {
+               *fnp = pdp->items->data;
+#ifdef AFS_NT40_ENV
+                ConvertAFSPath(fnp);
+#endif /* AFS_NT40_ENV */
+            } else if ( (strcmp(pdp->name, "-fid") == 0) ||
+                        (strcmp(pdp->name, "-vnode") == 0) ) {
+               *fnp = pdp->items->data;
+            } else if (strcmp(pdp->name, "-force") == 0)
+               force = 1;      /* global */
+            else if (strcmp(pdp->name, "-synthesize") == 0)
+               *slp = pdp->items->data;
+            else if (strcmp(pdp->name, "-realm") == 0)
+               *realmp = pdp->items->data;
+            else if (strcmp(pdp->name, "-wait") == 0)
+               waittime = atoi(pdp->items->data);
+            else if (strcmp(pdp->name, "-readlock") == 0)
+               readlock = 1;
+       }
+    }
+    return 0;
+}                              /* CmdProlog */
+
+int
+main(int argc, char **argv)
 {
-    afs_int32 code;
     struct cmd_syndesc *ts;
+    char *baseName;
+    int code;
 
-    strcpy(pnp, argv[0]);
+    /* try to get only the base name of this executable for use in logs */
+#ifdef AFS_NT40_ENV
+    char *p = strdup(argv[0]);
+    ConvertAFSPath(&p);
+    code = BreakUpPath(p, NULL, &baseName);
+    free(p);
+#else
+    code = BreakUpPath(argv[0], NULL, &baseName);
+#endif
+    if (code > 0)
+       strlcpy(pnp, baseName, AFSNAMEMAX);
+    else
+       strlcpy(pnp, argv[0], AFSPATHMAX);
+    free(baseName);
 
 #ifdef AFS_PTHREAD_ENV
-    assert(pthread_key_create(&uclient_key, NULL) == 0);
+    opr_Verify(pthread_key_create(&uclient_key, NULL) == 0);
 #endif
-    ts = cmd_CreateSyntax("read", readFile, CMD_REQUIRED,
+
+    ts = cmd_CreateSyntax("lock", lockFile, (void *)LockWrite, 0,
+                         "lock a file in AFS");
+    cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
+    cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
+    cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_Seek(ts, 4);
+    cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
+    cmd_AddParm(ts, "-waitseconds", CMD_SINGLE, CMD_OPTIONAL, "seconds to wait before giving up");
+    cmd_AddParm(ts, "-readlock", CMD_FLAG, CMD_OPTIONAL, "read lock only");
+
+    ts = cmd_CreateSyntax("fidlock", lockFile, (void *)LockWrite, 0,
+                         "lock by FID a file from AFS");
+    cmd_AddParm(ts, "-fid", CMD_SINGLE, CMD_REQUIRED,
+               "volume.vnode.uniquifier");
+    cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
+    cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_Seek(ts, 4);
+    cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
+    cmd_AddParm(ts, "-waitseconds", CMD_SINGLE, CMD_OPTIONAL, "seconds to wait before giving up");
+    cmd_AddParm(ts, "-readlock", CMD_FLAG, CMD_OPTIONAL, "read lock only");
+
+    ts = cmd_CreateSyntax("unlock", lockFile, (void *)LockRelease, 0,
+                         "unlock a file in AFS");
+    cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
+    cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
+    cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_Seek(ts, 4);
+    cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
+    cmd_AddParm(ts, "-waitseconds", CMD_SINGLE, CMD_OPTIONAL, "seconds to wait before giving up");
+
+    ts = cmd_CreateSyntax("fidunlock", lockFile, (void *)LockRelease, 0,
+                         "unlock by FID a file from AFS");
+    cmd_AddParm(ts, "-fid", CMD_SINGLE, CMD_REQUIRED,
+               "volume.vnode.uniquifier");
+    cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
+    cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_Seek(ts, 4);
+    cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
+    cmd_AddParm(ts, "-waitseconds", CMD_SINGLE, CMD_OPTIONAL, "seconds to wait before giving up");
+
+    ts = cmd_CreateSyntax("read", readFile, NULL, 0,
                          "read a file from AFS");
     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
-    cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *) 0);
+    cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
     cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
+    cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
 
-    ts = cmd_CreateSyntax("fidread", readFile, CMD_REQUIRED,
+    ts = cmd_CreateSyntax("fidread", readFile, CMD_REQUIRED, 0,
                          "read on a non AFS-client a file from AFS");
-    cmd_IsAdministratorCommand(ts);
-    cmd_AddParm(ts, "-fid", CMD_SINGLE, CMD_REQUIRED, "volume.vnode.uniquifier");
+    cmd_AddParm(ts, "-fid", CMD_SINGLE, CMD_REQUIRED,
+               "volume.vnode.uniquifier");
     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
-    cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *) 0);
+    cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
     cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
+    cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
 
-    ts = cmd_CreateSyntax("write", writeFile, CMD_REQUIRED,
+    ts = cmd_CreateSyntax("write", writeFile, NULL, 0,
                          "write a file into AFS");
-    cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "AFS-filename");
+    cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
-    cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *) 0);
+    cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
     cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
-    cmd_AddParm(ts, "-synthesize", CMD_SINGLE, CMD_OPTIONAL, "create data pattern of specified length instead reading from stdin");
+    cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
+               "overwrite existing file");
+    cmd_AddParm(ts, "-synthesize", CMD_SINGLE, CMD_OPTIONAL,
+               "create data pattern of specified length instead reading from stdin");
+    cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
 
-    ts = cmd_CreateSyntax("fidwrite", writeFile, CMD_REQUIRED,
+    ts = cmd_CreateSyntax("fidwrite", writeFile, CMD_REQUIRED, 0,
                          "write a file into AFS");
-    cmd_IsAdministratorCommand(ts);
-    cmd_AddParm(ts, "-vnode", CMD_SINGLE, CMD_REQUIRED, "volume.vnode.uniquifier");
+    cmd_AddParm(ts, "-vnode", CMD_SINGLE, CMD_REQUIRED,
+               "volume.vnode.uniquifier");
     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
-    cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *) 0);
+    cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
     cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
+    cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
+               "overwrite existing file");
+    cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
 
-    ts = cmd_CreateSyntax("append", writeFile, CMD_REQUIRED,
+    ts = cmd_CreateSyntax("append", writeFile, NULL, 0,
                          "append to a file in AFS");
-    cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "AFS-filename");
+    cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
-    cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *) 0);
+    cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
 
-    ts = cmd_CreateSyntax("fidappend", writeFile, CMD_REQUIRED,
+    ts = cmd_CreateSyntax("fidappend", writeFile, NULL, 0,
                          "append to a file in AFS");
-    cmd_IsAdministratorCommand(ts);
-    cmd_AddParm(ts, "-vnode", CMD_SINGLE, CMD_REQUIRED, "volume.vnode.uniquifier");
+    cmd_AddParm(ts, "-vnode", CMD_SINGLE, CMD_REQUIRED,
+               "volume.vnode.uniquifier");
     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
-    cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *) 0);
+    cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
 
-    code = cmd_Dispatch(argc, argv);
-    exit (0);
-}
+    if (afscp_Init(NULL) != 0)
+       exit(1);
 
-AFS_UNUSED
-afs_int32
-HandleLocalAuth(struct rx_securityClass **sc, afs_int32 *scIndex)
-{
-    static struct afsconf_dir *tdir = NULL;
-    afs_int32 code;
+    cmd_Dispatch(argc, argv);
 
-    *sc = NULL;
-    *scIndex = RX_SECIDX_NULL;
+    afscp_Finalize();
+    exit(0);
+} /* main */
 
-    tdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
-    if (!tdir) {
-        fprintf(stderr,"Could not open configuration directory: %s.\n",
-               AFSDIR_SERVER_ETC_DIRPATH);
-        return -1;
+/*!
+ * standardized way of parsing a File ID (FID) from command line input
+ *
+ * \param[in]  fidString       dot-delimited FID triple
+ * \param[out] fid             pointer to the AFSFid to fill in
+ *
+ * \post The FID pointed to by "fid" is filled in which the parsed Volume,
+ *       Vnode, and Uniquifier data.  The string should be in the format
+ *       of three numbers separated by dot (.) delimiters, representing
+ *       (in order) the volume id, vnode number, and uniquifier.
+ *       Example: "576821346.1.1"
+ */
+static int
+ScanFid(char *fidString, struct AFSFid *fid)
+{
+    int i = 0, code = 0;
+    long unsigned int f1, f2, f3;
+
+    if (fidString) {
+       i = sscanf(fidString, "%lu.%lu.%lu", &f1, &f2, &f3);
+       fid->Volume = (afs_uint32) f1;
+       fid->Vnode = (afs_uint32) f2;
+       fid->Unique = (afs_uint32) f3;
     }
-    code = afsconf_ClientAuth(tdir, sc, scIndex);
-    if (code) {
-        fprintf(stderr,"afsconf_ClientAuth returned %d\n", code);
-        return -1;
+    if (i != 3) {
+       fid->Volume = 0;
+       fid->Vnode = 0;
+       fid->Unique = 0;
+       code = EINVAL;
+       afs_com_err(pnp, code, "(invalid FID triple: %s)", fidString);
     }
-    return 0;
-}
 
-afs_int32
-AFS_Lookup(struct rx_connection *conn, AFSFid *dirfid, char *name,
-          AFSFid *outfid, AFSFetchStatus *outstatus, AFSFetchStatus
-          *dirstatus, AFSCallBack *callback, AFSVolSync *sync)
-{
-    afs_int32 code = VBUSY;
-    while (code == VBUSY) {
-       code = RXAFS_Lookup(conn, dirfid, name, outfid, outstatus, dirstatus,
-                           callback, sync);
-       if (code == VBUSY) {
-           fprintf(stderr, "waiting for busy AFS volume %u.\n",
-                   dirfid->Volume);
-#ifdef AFS_PTHREAD_ENV
-           sleep(10);
-#else
-           IOMGR_Sleep(10);
-#endif
-       }
-    }
     return code;
-}
+} /* ScanFid */
 
-afs_int32
-AFS_FetchStatus(struct rx_connection *conn, AFSFid *fid, AFSFetchStatus
-               *Status, AFSCallBack *callback, AFSVolSync *sync)
+/*!
+ * look up cell info and verify FID info from user input
+ *
+ * \param[in]  fidString       string containing FID info
+ * \param[in]  cellName        cell name string
+ * \param[in]  onlyRW          bool: 1 = RW vol only, 0 = any vol type
+ * \param[out] avfpp           pointer to venusfid info
+ *
+ * \post *avfpp will contain the VenusFid info found for the FID
+ *       given by the used in the string fidString and zero is
+ *       returned.  If not found, an appropriate afs error code
+ *       is returned and *avfpp will be NULL.
+ *
+ * \note Any non-NULL avfpp returned should later be freed with
+ *       afscp_FreeFid() when no longer needed.
+ */
+static afs_int32
+GetVenusFidByFid(char *fidString, char *cellName, int onlyRW,
+                 struct afscp_venusfid **avfpp)
 {
-    afs_int32 code = VBUSY;
-
-    while (code == VBUSY) {
-        code = RXAFS_FetchStatus(conn, fid, Status, callback, sync);
-       if (code == VBUSY) {
-           fprintf(stderr, "waiting for busy AFS volume %u.\n",
-                   fid->Volume);
-#ifdef AFS_PTHREAD_ENV
-           sleep(10);
-#else
-           IOMGR_Sleep(10);
-#endif
+    afs_int32 code = 0;
+    struct stat sbuf;
+    struct afscp_volume *avolp;
+
+    if (*avfpp == NULL) {
+       *avfpp = calloc(1, sizeof(struct afscp_venusfid));
+       if ( *avfpp == NULL ) {
+           code = ENOMEM;
+           return code;
        }
     }
-    return code;
-}
 
-afs_int32
-StartAFS_FetchData(struct rx_call *call, AFSFid *fid, afs_int32 pos,
-                  afs_int32 len)
-{
-    afs_int32 code = VBUSY;
-    while (code == VBUSY) {
-       code = StartRXAFS_FetchData (call, fid, pos, len);
-       if (code == VBUSY) {
-           fprintf(stderr, "waiting for busy AFS volume %u.\n",
-                   fid->Volume);
-#ifdef AFS_PTHREAD_ENV
-           sleep(10);
-#else
-           IOMGR_Sleep(10);
-#endif
-       }
+    if (cellName == NULL) {
+       (*avfpp)->cell = afscp_DefaultCell();
+    } else {
+       (*avfpp)->cell = afscp_CellByName(cellName, NULL);
+    }
+    if ((*avfpp)->cell == NULL) {
+       if (afscp_errno == 0)
+           code = EINVAL;
+       else
+           code = afscp_errno;
+       return code;
     }
-    return code;
-}
 
-afs_int32
-StartAFS_FetchData64(struct rx_call *call, AFSFid *fid, afs_int64 pos,
-                     afs_int64 len)
-{
-    afs_int32 code = VBUSY;
-    while (code == VBUSY) {
-       code = StartRXAFS_FetchData64 (call, fid, pos, len);
-       if (code == VBUSY) {
-           fprintf(stderr, "waiting for busy AFS volume %u.\n",
-                   fid->Volume);
-#ifdef AFS_PTHREAD_ENV
-           sleep(10);
-#else
-           IOMGR_Sleep(10);
-#endif
-       }
+    code = ScanFid(fidString, &((*avfpp)->fid));
+    if (code != 0) {
+       code = EINVAL;
+       return code;
     }
-    return code;
-}
 
-afs_int32
-StartAFS_StoreData(struct rx_call *call, AFSFid *fid, AFSStoreStatus *status,
-                  afs_int32 pos, afs_int32 len, afs_int32 len2)
-{
-    afs_int32 code = VBUSY;
-    while (code == VBUSY) {
-       code = StartRXAFS_StoreData (call, fid, status, pos, len, len2);
-       if (code == VBUSY) {
-           fprintf(stderr, "waiting for busy AFS volume %u.\n",
-                   fid->Volume);
-#ifdef AFS_PTHREAD_ENV
-           sleep(10);
-#else
-           IOMGR_Sleep(10);
-#endif
-       }
+    avolp = afscp_VolumeById((*avfpp)->cell, (*avfpp)->fid.Volume);
+    if (avolp == NULL) {
+       if (afscp_errno == 0)
+           code = ENOENT;
+       else
+           code = afscp_errno;
+       afs_com_err(pnp, code, "(finding volume %lu)",
+                   afs_printable_uint32_lu((*avfpp)->fid.Volume));
+       return code;
     }
-    return code;
-}
 
-afs_uint32
-StartAFS_StoreData64(struct rx_call *call, AFSFid *fid, AFSStoreStatus *status,
-                    afs_int64 pos, afs_int64 len, afs_int64 len2)
-{
-    afs_int32 code = VBUSY;
-    while (code == VBUSY) {
-       code = StartRXAFS_StoreData64 (call, fid, status, pos, len, len2);
-       if (code == VBUSY) {
-           fprintf(stderr, "waiting for busy AFS volume %u.\n",
-                   fid->Volume);
-#ifdef AFS_PTHREAD_ENV
-           sleep(10);
-#else
-           IOMGR_Sleep(10);
-#endif
+    if ( onlyRW && (avolp->voltype != RWVOL) ) {
+       avolp = afscp_VolumeByName((*avfpp)->cell, avolp->name, RWVOL);
+       if (avolp == NULL) {
+           if (afscp_errno == 0)
+               code = ENOENT;
+           else
+               code = afscp_errno;
+           afs_com_err(pnp, code, "(finding volume %lu)",
+                       afs_printable_uint32_lu((*avfpp)->fid.Volume));
+           return code;
        }
+       (*avfpp)->fid.Volume = avolp->id; /* is this safe? */
     }
-    return code;
-}
-
-afs_int32
-SRXAFSCB_CallBack(struct rx_call *rxcall, AFSCBFids *Fids_Array,
-                 AFSCBs *CallBack_Array)
-{
-    return 0;
-}
-
-afs_int32
-SRXAFSCB_InitCallBackState(struct rx_call *rxcall)
-{
-    return 0;
-}
 
-afs_int32
-SRXAFSCB_Probe(struct rx_call *rxcall)
-{
+    code = afscp_Stat((*avfpp), &sbuf);
+    if (code != 0) {
+       afs_com_err(pnp, code, "(stat failed with code %d)", code);
+       return code;
+    }
     return 0;
-}
+} /* GetVenusFidByFid */
 
-afs_int32
-SRXAFSCB_GetCE(struct rx_call *rxcall,
-              afs_int32 index,
-              AFSDBCacheEntry * ce)
-{
-    return(0);
-}
-
-afs_int32
-SRXAFSCB_GetLock(struct rx_call *rxcall,
-                afs_int32 index,
-                AFSDBLock * lock)
-{
-    return(0);
-}
-
-afs_int32
-SRXAFSCB_XStatsVersion(struct rx_call *rxcall,
-                      afs_int32 * versionNumberP)
+/*!
+ * Split a full path up into dirName and baseName components
+ *
+ * \param[in]  fullPath        can be absolute, relative, or local
+ * \param[out] dirName         pointer to output string or NULL
+ * \param[out] baseName        pointer to output string or NULL
+ *
+ * \post A buffer of appropriate size will be allocated into the output
+ *       parameter baseName and the rightmost full path component of the
+ *       fullPath copied into it; likewise, the other components of the
+ *       fullPath (minus the trailing path separator) will be placed into
+ *       the dirName output, which is also allocated to be the appropriate
+ *       size.  If either dirName or baseName are NULL, only the non-NULL
+ *       pointer will be allocated and filled in (but both can't be null
+ *       or it would be pointless) -- so the caller can retrieve, say,
+ *       only baseName if desired.  The return code is the number of
+ *       strings allocated and copied:
+ *       0 if neither dirName nor baseName could be filled in
+ *       1 if either dirName or baseName were filled in
+ *       2 if both dirName and baseName were filled in
+ */
+static int
+BreakUpPath(char *fullPath, char **dirName, char **baseName)
 {
-    return(0);
-}
+    char *lastSlash;
+    size_t dirNameLen = 0;
+    int code = 0, useDirName = 1, useBaseName = 1;
 
-afs_int32
-SRXAFSCB_GetXStats(struct rx_call *rxcall,
-                  afs_int32 clientVersionNumber,
-                  afs_int32 collectionNumber,
-                  afs_int32 * srvVersionNumberP,
-                  afs_int32 * timeP,
-                  AFSCB_CollData * dataP)
-{
-    return(0);
-}
+    if (fullPath == NULL) {
+       return code;
+    }
 
-afs_int32
-SRXAFSCB_ProbeUuid(struct rx_call *a_call, afsUUID *a_uuid)
-{
-    if ( !afs_uuid_equal(&uuid, a_uuid) )
-        return(1);
+    /* Track what we need to output and initialize output variables to NULL. */
+    if (dirName == NULL)
+       useDirName = 0;
     else
-        return(0);
-}
-
-
-afs_int32
-SRXAFSCB_WhoAreYou(struct rx_call *a_call, struct interfaceAddr *addr)
-{
-    return SRXAFSCB_TellMeAboutYourself(a_call, addr, NULL);
-}
-
-afs_int32
-SRXAFSCB_InitCallBackState2(struct rx_call *a_call, struct interfaceAddr *
-                           addr)
-{
-    return RXGEN_OPCODE;
-}
-
-afs_int32
-SRXAFSCB_InitCallBackState3(struct rx_call *a_call, afsUUID *a_uuid)
-{
-    return 0;
-}
-
-afs_int32
-SRXAFSCB_GetCacheConfig(struct rx_call *a_call, afs_uint32 callerVersion,
-                       afs_uint32 *serverVersion, afs_uint32 *configCount,
-                       cacheConfig *config)
-{
-    return RXGEN_OPCODE;
-}
-
-afs_int32
-SRXAFSCB_GetLocalCell(struct rx_call *a_call, char **a_name)
-{
-    return RXGEN_OPCODE;
-}
-
-afs_int32
-SRXAFSCB_GetCellServDB(struct rx_call *a_call, afs_int32 a_index,
-                      char **a_name, serverList *a_hosts)
-{
-    return RXGEN_OPCODE;
-}
-
-afs_int32
-SRXAFSCB_GetServerPrefs(struct rx_call *a_call, afs_int32 a_index,
-                       afs_int32 *a_srvr_addr, afs_int32 *a_srvr_rank)
-{
-    return RXGEN_OPCODE;
-}
-
-afs_int32
-SRXAFSCB_TellMeAboutYourself(struct rx_call *a_call, struct interfaceAddr *
-                            addr, Capabilities *capabilities)
-{
-#ifdef AFS_NT40_ENV
-    int code;
-    int cm_noIPAddr;                        /* number of client network interfaces */
-    int cm_IPAddr[CM_MAXINTERFACE_ADDR];    /* client's IP address in host order */
-    int cm_SubnetMask[CM_MAXINTERFACE_ADDR];/* client's subnet mask in host order*/
-    int cm_NetMtu[CM_MAXINTERFACE_ADDR];    /* client's MTU sizes */
-    int cm_NetFlags[CM_MAXINTERFACE_ADDR];  /* network flags */
-    int i;
-
-    cm_noIPAddr = CM_MAXINTERFACE_ADDR;
-    code = syscfg_GetIFInfo(&cm_noIPAddr,
-                            cm_IPAddr, cm_SubnetMask,
-                            cm_NetMtu, cm_NetFlags);
-    if (code > 0) {
-        /* return all network interface addresses */
-        addr->numberOfInterfaces = cm_noIPAddr;
-        for ( i=0; i < cm_noIPAddr; i++ ) {
-            addr->addr_in[i] = cm_IPAddr[i];
-            addr->subnetmask[i] = cm_SubnetMask[i];
-            addr->mtu[i] = (rx_mtu == -1 || (rx_mtu != -1 && cm_NetMtu[i] < rx_mtu)) ?
-                cm_NetMtu[i] : rx_mtu;
-        }
-    } else {
-        addr->numberOfInterfaces = 0;
-    }
-#else
-    addr->numberOfInterfaces = 0;
-#ifdef notdef
-    /* return all network interface addresses */
-    addr->numberOfInterfaces = afs_cb_interface.numberOfInterfaces;
-    for ( i=0; i < afs_cb_interface.numberOfInterfaces; i++) {
-        addr->addr_in[i] = ntohl(afs_cb_interface.addr_in[i]);
-        addr->subnetmask[i] = ntohl(afs_cb_interface.subnetmask[i]);
-        addr->mtu[i] = ntohl(afs_cb_interface.mtu[i]);
+       *dirName = NULL;
+    if (baseName == NULL)
+       useBaseName = 0;
+    else
+       *baseName = NULL;
+    if (!useBaseName && !useDirName) {
+       /* would be pointless to continue -- must be error in call */
+       return code;
     }
-#endif
-#endif
-
-    addr->uuid = uuid;
-
-    if (capabilities) {
-        afs_uint32 *dataBuffP;
-        afs_int32 dataBytes;
-
-        dataBytes = 1 * sizeof(afs_uint32);
-        dataBuffP = (afs_uint32 *) xdr_alloc(dataBytes);
-        dataBuffP[0] = CLIENT_CAPABILITY_ERRORTRANS;
-        capabilities->Capabilities_len = dataBytes / sizeof(afs_uint32);
-        capabilities->Capabilities_val = dataBuffP;
+    lastSlash = strrchr(fullPath, '/');
+    if (lastSlash != NULL) {
+       /* then lastSlash points to the last path separator in fullPath */
+       if (useDirName) {
+           dirNameLen = strlen(fullPath) - strlen(lastSlash);
+           *dirName = strdup(fullPath);
+           if (*dirName != NULL) {
+               code++;
+               /* Wastes some memory, but avoids needing libroken. */
+               *dirName[dirNameLen] = '\0';
+           }
+       }
+       if (useBaseName) {
+           lastSlash++;
+           *baseName = strdup(lastSlash);
+           if (*baseName != NULL)
+               code++;
+       }
+    } else {
+       /* there are no path separators in fullPath -- it's just a baseName */
+       if (useBaseName) {
+           *baseName = strdup(fullPath);
+           if (*baseName != NULL)
+               code++;
+       }
     }
-    return 0;
-}
-
-afs_int32
-SRXAFSCB_GetCellByNum(struct rx_call *a_call, afs_int32 a_cellnum,
-                     char **a_name, serverList *a_hosts)
-{
-    return RXGEN_OPCODE;
-}
-
-afs_int32
-SRXAFSCB_GetCE64(struct rx_call *a_call, afs_int32 a_index,
-                struct AFSDBCacheEntry64 *a_result)
-{
-    return RXGEN_OPCODE;
-}
+    return code;
+} /* BreakUpPath */
 
-void *
-InitializeCBService_LWP(void *unused)
+/*!
+ * Get the VenusFid info available for the file at AFS path 'fullPath'.
+ * Works without pioctls/afsd by using libafscp.  Analogous to
+ * get_file_cell() in the previous iteration of afsio.
+ *
+ * \param[in]  fullPath        the file name
+ * \param[in]  cellName        the cell name to look up
+ * \param[out] avfpp           pointer to Venus FID info to be filled in
+ *
+ * \post If the path resolves successfully (using afscp_ResolvePath),
+ *       then vfpp will contain the Venus FID info (cell info plus
+ *       AFSFid) of the last path segment in fullPath.
+ */
+static afs_int32
+GetVenusFidByPath(char *fullPath, char *cellName,
+                  struct afscp_venusfid **avfpp)
 {
-    struct rx_securityClass *CBsecobj;
-    struct rx_service *CBService;
+    afs_int32 code = 0;
 
-    afs_uuid_create(&uuid);
+    if (fullPath == NULL) {
+       return -1;
+    }
 
-    CBsecobj = (struct rx_securityClass *)rxnull_NewServerSecurityObject();
-    if (!CBsecobj) {
-       fprintf(stderr,"rxnull_NewServerSecurityObject failed for callback service.\n");
-       exit(1);
+    if (cellName != NULL) {
+       code = (afs_int32) afscp_SetDefaultCell(cellName);
+       if (code != 0) {
+           return code;
+       }
     }
-    CBService = rx_NewService(0, 1, "afs", &CBsecobj, 1,
-                             RXAFSCB_ExecuteRequest);
-    if (!CBService) {
-       fprintf(stderr,"rx_NewService failed for callback service.\n");
-       exit(1);
+
+    *avfpp = afscp_ResolvePath(fullPath);
+    if (*avfpp == NULL) {
+       if (afscp_errno == 0)
+           code = ENOENT;
+       else
+           code = afscp_errno;
     }
-    rx_StartServer(1);
-    return 0;
-}
 
+    return code;
+} /* GetVenusFidByPath */
 
-int
-InitializeCBService(void)
+static int
+lockFile(struct cmd_syndesc *as, void *arock)
 {
-#define RESTOOL_CBPORT 7102
-#define MAX_PORT_TRIES 1000
-#define LWP_STACK_SIZE (16 * 1024)
-    afs_int32 code;
-#ifdef AFS_PTHREAD_ENV
-    pthread_t CBservicePid;
-    pthread_attr_t tattr;
-#else
-    PROCESS CBServiceLWP_ID, parentPid;
-#endif
-    int InitialCBPort;
-    int CBPort;
+    char *fname = NULL;
+    char *cell = NULL;
+    char *realm = NULL;
+    afs_int32 code = 0;
+    struct AFSFetchStatus OutStatus;
+    struct afscp_venusfid *avfp = NULL;
+    char *buf = 0;
+    char ipv4_addr[16];
+    int locktype = (int)(intptr_t) arock;
 
-#ifndef NO_AFS_CLIENT
-    if (!CBServiceNeeded)
-        return 0;
-#endif
-#ifndef AFS_PTHREAD_ENV
-    code = LWP_InitializeProcessSupport(LWP_MAX_PRIORITY - 2, &parentPid);
-    if (code != LWP_SUCCESS) {
-       fprintf(stderr,"Unable to initialize LWP support, code %d\n",
-               code);
-       exit(1);
-    }
+#ifdef AFS_NT40_ENV
+    /* stdout on Windows defaults to _O_TEXT mode */
+    _setmode(1, _O_BINARY);
 #endif
 
-#if defined(AFS_AIX_ENV) || defined(AFS_SUN_ENV) || defined(AFS_DEC_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI_ENV)
-    srandom(getpid());
-    InitialCBPort = RESTOOL_CBPORT + random() % 1000;
-#else /* AFS_AIX_ENV || AFS_SUN_ENV || AFS_OSF_ENV || AFS_SGI_ENV */
-#if defined(AFS_HPUX_ENV)
-    srand48(getpid());
-    InitialCBPort = RESTOOL_CBPORT + lrand48() % 1000;
-#else /* AFS_HPUX_ENV */
-#if defined AFS_NT40_ENV
-    srand(_getpid());
-    InitialCBPort = RESTOOL_CBPORT + rand() % 1000;
-#else /* AFS_NT40_ENV */
-    srand(getpid());
-    InitialCBPort = RESTOOL_CBPORT + rand() % 1000;
-#endif /* AFS_NT40_ENV */
-#endif /* AFS_HPUX_ENV */
-#endif /* AFS_AIX_ENV || AFS_SUN_ENV || AFS_OSF_ENV || AFS_SGI_ENV */
-
-    CBPort = InitialCBPort;
-    do {
-       code = rx_Init(htons(CBPort));
-       if (code) {
-           if ((code == RX_ADDRINUSE) &&
-               (CBPort < MAX_PORT_TRIES + InitialCBPort)) {
-               CBPort++;
-           } else if (CBPort < MAX_PORT_TRIES + InitialCBPort) {
-               fprintf(stderr, "rx_Init didn't succeed for callback service."
-                       " Tried port numbers %d through %d\n",
-                       InitialCBPort, CBPort);
-               exit(1);
-           } else {
-               fprintf(stderr,"Couldn't initialize callback service "
-                       "because too many users are running this program. "
-                       "Try again later.\n");
-               exit(1);
-           }
-       }
-    } while(code);
-#ifdef AFS_PTHREAD_ENV
-    assert(pthread_attr_init(&tattr) == 0);
-    assert(pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED) == 0);
-    assert(pthread_create(
-              &CBservicePid, &tattr, InitializeCBService_LWP, 0)
-          == 0);
-#else
-    code = LWP_CreateProcess(InitializeCBService_LWP, LWP_STACK_SIZE,
-                            LWP_MAX_PRIORITY - 2, (int *) 0, "CBService",
-                            &CBServiceLWP_ID);
-    if (code != LWP_SUCCESS) {
-       fprintf(stderr,"Unable to create the callback service LWP, code %d\n",
-               code);
-       exit(1);
-    }
-#endif
-    return 0;
-}
+    gettimeofday(&starttime, &Timezone);
 
-int
-ScanVnode(char *fname, char *cell)
-{
-    afs_int32 i, code = 0;
+    CmdProlog(as, &cell, &realm, &fname, NULL);
+    afscp_AnonymousAuth(1);
+    if (clear)
+       afscp_Insecure();
 
-    SetCellFname(cell);
-    i = sscanf(fname, "%u.%u.%u",
-              &PioctlInputs.fid.Volume,
-              &PioctlInputs.fid.Vnode,
-              &PioctlInputs.fid.Unique);
-    if (i != 3) {
-       PioctlInputs.fid.Volume = 0;
-       PioctlInputs.fid.Vnode = 0;
-       PioctlInputs.fid.Unique = 0;
-        fprintf(stderr,"fs: invalid vnode triple: %s\n", fname);
-        code = EINVAL;
-    }
-    /*
-     * The following is used to handle the case of unknown uniquifier. We
-     * just need a valid reference to the volume to direct the RPC to the
-     * right fileserver. Therefore we take the root directory of the volume.
-     */
-    if (PioctlInputs.fid.Unique == 0) {
-       PioctlInputs.int32s[0] = PioctlInputs.fid.Vnode;
-       PioctlInputs.fid.Vnode = 1;
-       PioctlInputs.fid.Unique = 1;
-    }
-    return code;
-}
+    if ((locktype == LockWrite) && readlock)
+       locktype = LockRead;
 
-int
-VLDBInit(int noAuthFlag, struct afsconf_cell *info)
-{
-    afs_int32 code;
-
-    code = ugen_ClientInit(noAuthFlag, (char *) AFSDIR_CLIENT_ETC_DIRPATH,
-                           info->name, 0, &uclient,
-                           NULL, pnp, rxkad_clear,
-                           VLDB_MAXSERVERS, AFSCONF_VLDBSERVICE, 50,
-                           0, 0, USER_SERVICE_ID);
-    rxInitDone = 1;
-    return code;
-}
+    if (realm != NULL)
+       afscp_SetDefaultRealm(realm);
 
-afs_int32
-get_vnode_hosts(char *fname, char **cellp, afs_int32 *hosts, AFSFid *Fid,
-               int onlyRW)
-{
-    struct afsconf_dir *tdir;
-    struct vldbentry vldbEntry;
-    afs_int32 i, j, code, *h, len;
-    struct afsconf_cell info;
-    afs_int32 mask;
-
-    tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
-    if (!tdir) {
-        fprintf(stderr,"Could not process files in configuration directory "
-               "(%s).\n",AFSDIR_CLIENT_ETC_DIRPATH);
-        return -1;
-    }
-    if (!*cellp) {
-       len = MAXCELLCHARS;
-       *cellp = (char *) malloc(MAXCELLCHARS);
-       code = afsconf_GetLocalCell(tdir, *cellp, len);
-       if (code) return code;
-    }
-    code = afsconf_GetCellInfo(tdir, *cellp, AFSCONF_VLDBSERVICE, &info);
-    if (code) {
-        fprintf(stderr,"fs: cell %s not in %s/CellServDB\n",
-               *cellp, AFSDIR_CLIENT_ETC_DIRPATH);
-        return code;
-    }
+    if (cell != NULL)
+       afscp_SetDefaultCell(cell);
 
-    i = sscanf(fname, "%u.%u.%u", &Fid->Volume, &Fid->Vnode, &Fid->Unique);
-    if (i != 3) {
-       fprintf(stderr,"fs: invalid vnode triple: %s\n", fname);
-       return 1;
-    }
-    code = VLDBInit(1, &info);
-    if (code == 0) {
-        code = ubik_VL_GetEntryByID(uclient, 0, Fid->Volume,
-                                   -1, &vldbEntry);
-        if (code == VL_NOENT)
-            fprintf(stderr,"fs: volume %u does not exist in this cell.\n",
-                   Fid->Volume);
-        if (code) return code;
+    if (useFid)
+       code = GetVenusFidByFid(fname, cell, 0, &avfp);
+    else
+       code = GetVenusFidByPath(fname, cell, &avfp);
+    if (code != 0) {
+       afs_com_err(pnp, code, "(file not found: %s)", fname);
+       afscp_FreeFid(avfp);
+       return code;
     }
-    h = hosts;
-    mask = VLSF_RWVOL;
-    if (!onlyRW) mask |= VLSF_RWVOL;
-    for (i=0, j=0; j<vldbEntry.nServers; j++) {
-        if (vldbEntry.serverFlags[j] & mask) {
-            *h++ = ntohl(vldbEntry.serverNumber[j]);
-            i++;
-        }
+
+retry:
+    code = afscp_GetStatus(avfp, &OutStatus);
+    if (code != 0) {
+       afs_inet_ntoa_r(avfp->cell->fsservers[0]->addrs[0], ipv4_addr);
+       afs_com_err(pnp, code, "(failed to get status of file %s from"
+                   "server %s, code = %d)", fname, ipv4_addr, code);
+       afscp_FreeFid(avfp);
+       return code;
     }
-    for (; i<AFS_MAXHOSTS; i++) *h++ = 0;
-    return 0;
-}
 
-/* get_file_cell()
- *     Determine which AFS cell file 'fn' lives in, the list of servers that
- *     offer it, and the FID.
- */
-afs_int32
-get_file_cell(char *fn, char **cellp, afs_int32 hosts[AFS_MAXHOSTS], AFSFid *Fid,
-             struct AFSFetchStatus *Status, afs_int32 create)
-{
-    afs_int32 code;
-    char buf[256];
-    struct ViceIoctl status;
-    int j;
-    afs_int32 *Tmpafs_int32;
-
-    memset( Status, 0, sizeof(struct AFSFetchStatus));
-    memset(buf, 0, sizeof(buf));
-    status.in_size = 0;
-    status.out_size = sizeof(buf);
-    status.in = buf;
-    status.out = buf;
-    errno = 0;
-    code = pioctl(fn, VIOC_FILE_CELL_NAME, &status, 0);
-    if (code && create) {
-       char *c;
-       int fd;
-       strcpy(buf,fn);
-#ifdef AFS_NT40_ENV
-        c = strrchr(buf,'\\');
-#else
-        c = strrchr(buf,'/');
-#endif
-       if (c) {
-           *c = 0;
-           code = pioctl(buf,VIOC_FILE_CELL_NAME, &status, 0);
-           if (!code) {
-               fd = open(fn, O_CREAT, 0644);
-               close(fd);
-           }
-           code = pioctl(fn, VIOC_FILE_CELL_NAME, &status, 0);
+    if (locktype != LockRelease) {
+       while (OutStatus.lockCount != 0) {
+           code = afscp_WaitForCallback(avfp, waittime);
+           if ((code == -1) && (afscp_errno == ETIMEDOUT))
+               break;
+           if ((code = afscp_GetStatus(avfp, &OutStatus)) != 0)
+               break;
        }
-    }
-    if (code) {
-       fprintf(stderr, "Unable to determine cell for %s\n", fn);
-       if (errno) {
-           perror(fn);
-           if (errno == EINVAL)
-               fprintf(stderr, "(File might not be in AFS)\n");
-       } else
-           afs_com_err(pnp, code, (char *) 0);
     } else {
-       *cellp = (char *) malloc(strlen(buf)+1);
-       strcpy(*cellp, buf);
-       SetCellFname(*cellp);
-       memset(buf, 0, sizeof(buf));
-       status.in = 0;
-       status.in_size = 0;
-       status.out = buf;
-       status.out_size = sizeof(buf);
-       code = pioctl(fn, VIOCWHEREIS, &status, 0);
-       if (code) {
-           fprintf(stderr, "Unable to determine fileservers for %s\n", fn);
-           if (errno) {
-               perror(fn);
-           }
-           else
-               afs_com_err(pnp, code, (char *) 0);
-       } else {
-           Tmpafs_int32 = (afs_int32 *)buf;
-           for (j=0;j<AFS_MAXHOSTS;++j) {
-               hosts[j] = Tmpafs_int32[j];
-               if (!Tmpafs_int32[j])
-                   break;
-           }
-       }
-       memset(buf, 0, sizeof(buf));
-       status.in_size = 0;
-       status.out_size = sizeof(buf);
-       status.in = 0;
-       status.out = buf;
-       code = pioctl(fn, VIOCGETFID, &status, 0);
-       if (code) {
-           fprintf(stderr, "Unable to determine FID for %s\n", fn);
-           if (errno) {
-               perror(fn);
-           } else {
-               afs_com_err(pnp, code, (char *) 0);
-           }
-       } else {
-           Tmpafs_int32 = (afs_int32 *)buf;
-           Fid->Volume = Tmpafs_int32[1];
-           Fid->Vnode = Tmpafs_int32[2];
-           Fid->Unique = Tmpafs_int32[3];
+       if (OutStatus.lockCount == 0) {
+           code = -1;
        }
     }
-    return code;
-}
 
-int
-DestroyConnections(void)
-{
-    int i;
-
-    if (!ConnLookupInitialized) return 0;
-    for (i = 0; i < MAX_HOSTS; i++) {
-        if (!ConnLookup[i].conn) break;
-       RXAFS_GiveUpAllCallBacks(ConnLookup[i].conn);
-       rx_DestroyConnection(ConnLookup[i].conn);
+    if (!code) {
+       code = afscp_Lock(avfp, locktype);
+       if ((code == -1) && (afscp_errno == EWOULDBLOCK))
+           goto retry;
     }
-    if (!rxInitDone)
-       rx_Finalize();
-    return 0;
-}
+    afscp_FreeFid(avfp);
 
+    if (buf != NULL)
+       free(buf);
 
-int
-LogErrors (int level, const char *fmt, ...)
-{
-    va_list ap;
+    if (code != 0)
+       afs_com_err(pnp, code, "(failed to change lock status: %d)", afscp_errno);
 
-    va_start(ap, fmt);
-    return vfprintf(stderr, fmt, ap);
-}
+    return code;
+} /* lockFile */
 
-int
+static int
 readFile(struct cmd_syndesc *as, void *unused)
 {
-    char *fname;
-    char *cell = 0;
-    afs_int32 code;
-    afs_int32 hosts[AFS_MAXHOSTS];
-    AFSFid Fid;
-    int j;
-    struct rx_connection *RXConn;
-    struct cellLookup *cl;
-    struct rx_call *tcall;
-    struct AFSVolSync tsync;
+    char *fname = NULL;
+    char *cell = NULL;
+    char *realm = NULL;
+    afs_int32 code = 0;
     struct AFSFetchStatus OutStatus;
-    struct AFSCallBack CallBack;
+    struct afscp_venusfid *avfp = NULL;
     afs_int64 Pos;
     afs_int32 len;
-    afs_int64 length, Len;
-    u_char vnode = 0;
-    u_char first = 1;
+    afs_int64 length = 0, Len;
     int bytes;
     int worstCode = 0;
     char *buf = 0;
+    char ipv4_addr[16];
     int bufflen = BUFFLEN;
 
 #ifdef AFS_NT40_ENV
@@ -970,318 +762,277 @@ readFile(struct cmd_syndesc *as, void *unused)
     _setmode(1, _O_BINARY);
 #endif
 
-    if (as->name[0] == 'f')
-       vnode = 1;
-    if (as->parms[2].items)
-       verbose = 1;
-    if (as->parms[3].items) {
-       md5sum = 1;
+    gettimeofday(&starttime, &Timezone);
+
+    CmdProlog(as, &cell, &realm, &fname, NULL);
+    afscp_AnonymousAuth(1);
+    if (clear)
+       afscp_Insecure();
+
+    if (md5sum)
        MD5_Init(&md5);
-    }
 
-    CBServiceNeeded = 1;
-    InitializeCBService();
+    if (realm != NULL)
+       afscp_SetDefaultRealm(realm);
+
+    if (cell != NULL)
+       afscp_SetDefaultCell(cell);
 
-    gettimeofday (&starttime, &Timezone);
-    fname = as->parms[0].items->data;
-    cell = 0;
-    if (as->parms[1].items)
-       cell = as->parms[1].items->data;
-    if (vnode)
-       code = get_vnode_hosts(fname, &cell, hosts, &Fid, 1);
+    if (useFid)
+       code = GetVenusFidByFid(fname, cell, 0, &avfp);
     else
-        code = get_file_cell(fname, &cell, hosts, &Fid, &OutStatus, 0);
-    if (code) {
-        fprintf(stderr,"File not found %s\n", fname);
-        return code;
+       code = GetVenusFidByPath(fname, cell, &avfp);
+    if (code != 0) {
+       afscp_FreeFid(avfp);
+       afs_com_err(pnp, code, "(file not found: %s)", fname);
+       return code;
     }
-    if (Fid.Vnode & 1) {
-       fprintf(stderr,"%s is a directory, not a file\n", fname);
-       return ENOENT;
+
+    if (avfp->fid.Vnode & 1) {
+       code = ENOENT;
+       afs_com_err(pnp, code, "(%s is a directory, not a file)", fname);
+       afscp_FreeFid(avfp);
+       return code;
     }
-    cl = FindCell(cell);
-    for (j=0;j<AFS_MAXHOSTS;++j) {
-       int useHost;
-
-        if (first && as->parms[6].items) {
-           afs_uint32 fields, ip1, ip2, ip3, ip4;
-           fields = sscanf(as->parms[6].items->data, "%d.%d.%d.%d",
-                           &ip1, &ip2, &ip3, &ip4);
-           useHost = (ip1 << 24) + (ip2 << 16) + (ip3 << 8) + ip4;
-           j--;
-        } else {
-            if (!hosts[j])
-                break;
-           useHost = hosts[j];
-       }
-       first = 0;
-        RXConn = FindRXConnection(useHost, htons(AFSCONF_FILEPORT), 1,
-                                 cl->sc, cl->scIndex);
-        if (!RXConn) {
-            fprintf(stderr,"rx_NewConnection failed to server 0x%X\n",
-                    useHost);
-            continue;
-        }
-        code = AFS_FetchStatus(RXConn, &Fid, &OutStatus, &CallBack, &tsync);
-        if (code) {
-           fprintf(stderr,"RXAFS_FetchStatus failed to server 0x%X for"
-                   " file %s, code was %d\n",
-                  useHost, fname, code);
-          continue;
-       }
-        gettimeofday(&opentime, &Timezone);
-       if (verbose) {
-            seconds = (float)(opentime.tv_sec + opentime.tv_usec *.000001
-               -starttime.tv_sec - starttime.tv_usec *.000001);
-           fprintf(stderr,"Startup to find the file took %.3f sec.\n",
-                   seconds);
-       }
-       Len = OutStatus.Length_hi;
-       Len <<= 32;
-       Len += OutStatus.Length;
-       ZeroInt64(Pos);
-       {
-           afs_uint32 high, low;
-
-            tcall = rx_NewCall(RXConn);
-            code = StartAFS_FetchData64 (tcall, &Fid, Pos, Len);
-            if (code == RXGEN_OPCODE) {
-               afs_int32 tmpPos,  tmpLen;
-               tmpPos = (afs_int32)Pos; tmpLen = (afs_int32)Len;
-                code = StartAFS_FetchData (tcall, &Fid, tmpPos, tmpLen);
-               bytes = rx_Read(tcall, (char *)&low, sizeof(afs_int32));
-               length = ntohl(low);
-               if (bytes != 4) code = -3;
-            } else if (!code) {
-                bytes = rx_Read(tcall, (char *)&high, 4);
-               length = ntohl(high);
-               length <<= 32;
-                bytes += rx_Read(tcall, (char *)&low, 4);
-               length += ntohl(low);
-               if (bytes != 8) code = -3;
-            }
-            if (code) {
-                if (code == RXGEN_OPCODE) {
-                    fprintf(stderr, "File server for %s might not be running a"
-                           " multi-resident AFS server\n",
-                           fname);
-               } else {
-                    fprintf(stderr, "%s for %s ended with error code %d\n",
-                            (char *) &as->name, fname, code);
-                   exit(1);
-               }
-            }
-           if (length > bufflen)
-               len = bufflen;
-           else
-               len = (afs_int32) length;
-           buf = (char *)malloc(len);
-           if (!buf) {
-               fprintf(stderr, "couldn't allocate buffer\n");
-               exit(1);
-           }
-           while (!code && NonZeroInt64(length)) {
-               if (length > bufflen)
-                   len = bufflen;
-               else
-                   len = (afs_int32) length;
-               bytes = rx_Read(tcall, (char *) buf, len);
-               if (bytes != len) {
-                   code = -3;
-               }
-               if (md5sum)
-                   MD5_Update(&md5, buf, len);
-               if (!code)
-                   write(1, buf, len);
-               length -= len;
-               xfered += len;
-               gettimeofday(&now, &Timezone);
-               if (verbose)
-                   printDatarate();
-           }
-           worstCode = code;
-           code = EndRXAFS_FetchData (tcall, &OutStatus, &CallBack, &tsync);
-           rx_EndCall(tcall, 0);
-           if (!worstCode)
-               worstCode = code;
-       }
-        break;
+
+    code = afscp_GetStatus(avfp, &OutStatus);
+    if (code != 0) {
+       afs_inet_ntoa_r(avfp->cell->fsservers[0]->addrs[0], ipv4_addr);
+       afs_com_err(pnp, code, "(failed to get status of file %s from"
+                   "server %s, code = %d)", fname, ipv4_addr, code);
+       afscp_FreeFid(avfp);
+       return code;
     }
-    gettimeofday(&readtime, &Timezone);
-    if (worstCode) {
-       fprintf(stderr,"%s failed with code %d\n",
-               (char *) &as->name, worstCode);
-    } else {
-        if (md5sum) {
-           afs_uint32 md5int[4];
-           char *p;
-           MD5_Final((char *) &md5int[0], &md5);
-#ifdef AFS_NT40_ENV
-            p = strrchr(fname,'\\');
-#else
-            p = strrchr(fname,'/');
-#endif
-            if (p)
-                p++;
-           else
-                p = fname;
-
-           fprintf(stderr, "%08x%08x%08x%08x  %s\n",
-                    htonl(md5int[0]), htonl(md5int[1]),
-                   htonl(md5int[2]), htonl(md5int[3]), p);
-        }
-       if(verbose) {
-            seconds = (float)(readtime.tv_sec + readtime.tv_usec *.000001
-               -opentime.tv_sec - opentime.tv_usec *.000001);
-            fprintf(stderr,"Transfer of %llu bytes took %.3f sec.\n",
-                   xfered, seconds);
-            datarate = (xfered >> 20) / seconds;
-            fprintf(stderr,"Total data rate = %.03f MB/sec. for read\n",
-                   datarate);
+
+    gettimeofday(&opentime, &Timezone);
+    if (verbose)
+       fprintf(stderr, "Startup to find the file took %.3f sec.\n",
+               time_elapsed(&starttime, &opentime));
+    Len = OutStatus.Length_hi;
+    Len <<= 32;
+    Len += OutStatus.Length;
+    ZeroInt64(Pos);
+    buf = calloc(bufflen, sizeof(char));
+    if (buf == NULL) {
+       code = ENOMEM;
+       afs_com_err(pnp, code, "(cannot allocate buffer)");
+       afscp_FreeFid(avfp);
+       return code;
+    }
+    length = Len;
+    while (!code && NonZeroInt64(length)) {
+       if (length > bufflen)
+           len = bufflen;
+       else
+           len = (afs_int32) length;
+       bytes = afscp_PRead(avfp, buf, len, Pos);
+       if (bytes != len)
+           code = -3; /* what error name should we use here? */
+       if (md5sum)
+           MD5_Update(&md5, buf, len);
+       if (code == 0) {
+           len = write(1, buf, len); /* to stdout */
+           if (len == 0)
+               code = errno;
        }
+       length -= len;
+       xfered += len;
+       if (verbose)
+           printDatarate();
+       Pos += len;
+       worstCode = code;
     }
-    DestroyConnections();
+    afscp_FreeFid(avfp);
+
+    gettimeofday(&readtime, &Timezone);
+    if (md5sum)
+       summarizeMD5(fname);
+    if (verbose)
+       summarizeDatarate(&readtime, "read");
+    if (buf != NULL)
+       free(buf);
+
     return worstCode;
-}
+} /* readFile */
 
-int
+static int
 writeFile(struct cmd_syndesc *as, void *unused)
 {
     char *fname = NULL;
-    char *cell = 0;
-    afs_int32 code, localcode = 0;
-    afs_int32 hosts[AFS_MAXHOSTS];
-    afs_uint32 useHost;
-    AFSFid Fid;
-    struct rx_connection *RXConn;
-    struct cellLookup *cl;
-    struct rx_call *tcall;
-    struct AFSVolSync tsync;
+    char *cell = NULL;
+    char *sSynthLen = NULL;
+    char *realm = NULL;
+    afs_int32 code = 0;
+    afs_int32 byteswritten;
     struct AFSFetchStatus OutStatus;
     struct AFSStoreStatus InStatus;
-    struct AFSCallBack CallBack;
+    struct afscp_venusfid *dirvfp = NULL, *newvfp = NULL;
     afs_int64 Pos;
     afs_int64 length, Len, synthlength = 0, offset = 0;
-    u_char vnode = 0;
     afs_int64 bytes;
-    int worstCode = 0;
-    int append = 0;
     int synthesize = 0;
-    afs_int32 byteswritten;
+    int overWrite = 0;
     struct wbuf *bufchain = 0;
     struct wbuf *previous, *tbuf;
+    char *dirName = NULL;
+    char *baseName = NULL;
+    char ipv4_addr[16];
 
 #ifdef AFS_NT40_ENV
     /* stdin on Windows defaults to _O_TEXT mode */
     _setmode(0, _O_BINARY);
 #endif
 
-    if (as->name[0] == 'f') {
-       vnode = 1;
-        if (as->name[3] == 'a')
-           append = 1;
-    } else
-        if (as->name[0] == 'a')
-           append = 1;
-    if (as->parms[2].items)
-       verbose = 1;
-    if (as->parms[3].items)
-       md5sum = 1;
-    if (as->parms[4].items) {
-       code = util_GetInt64(as->parms[4].items->data, &synthlength);
-       if (code) {
-           fprintf(stderr, "Invalid value for synthesize length %s\n",
-                   as->parms[4].items->data);
-           return code;
+    CmdProlog(as, &cell, &realm, &fname, &sSynthLen);
+    afscp_AnonymousAuth(1);
+    if (clear)
+       afscp_Insecure();
+
+    if (realm != NULL)
+       afscp_SetDefaultRealm(realm);
+
+    if (cell != NULL)
+       afscp_SetDefaultCell(cell);
+
+    if (sSynthLen) {
+       code = util_GetInt64(sSynthLen, &synthlength);
+       if (code != 0) {
+           afs_com_err(pnp, code, "(invalid value for synthesize length %s)",
+                       sSynthLen);
+           goto cleanup;
        }
        synthesize = 1;
     }
-    CBServiceNeeded = 1;
-    InitializeCBService();
 
-    if (as->parms[0].items)
-       fname = as->parms[0].items->data;
+    if (useFid) {
+       code = GetVenusFidByFid(fname, cell, 1, &newvfp);
+       if (code != 0) {
+           afs_com_err(pnp, code, "(GetVenusFidByFid returned code %d)", code);
+           goto cleanup;
+       }
+    } else {
+       code = GetVenusFidByPath(fname, cell, &newvfp);
+       if (code == 0) { /* file was found */
+           if (force)
+               overWrite = 1;
+           else if (!append) {
+               /*
+                * file cannot already exist if specified by path and not
+                * appending to it unless user forces overwrite
+                */
+               code = EEXIST;
+               afs_com_err(pnp, code, "(use -force to overwrite)");
+               goto cleanup;
+           }
+       } else { /* file not found */
+           if (append) {
+               code = ENOENT;
+               afs_com_err(pnp, code, "(cannot append to non-existent file)");
+               goto cleanup;
+           }
+       }
+       if (!append && !overWrite) { /* must create a new file in this case */
+           if ( BreakUpPath(fname, &dirName, &baseName) != 2 ) {
+               code = EINVAL;
+               afs_com_err(pnp, code, "(must provide full AFS path)");
+               goto cleanup;
+           }
 
-    cell = 0;
-    if (as->parms[1].items) cell = as->parms[1].items->data;
-    if (vnode) {
-       code = get_vnode_hosts(fname, &cell, hosts, &Fid, 1);
-       if (code)
-           return code;
-    } else
-        code = get_file_cell(fname, &cell, hosts, &Fid, &OutStatus, append ? 0 : 1);
-    if (code) {
-        fprintf(stderr,"File or directory not found: %s\n",
-                    fname);
-        return code;
-    }
-    if (Fid.Vnode & 1) {
-       fprintf(stderr,"%s is a directory, not a file\n", fname);
-       return ENOENT;
+           code = GetVenusFidByPath(dirName, cell, &dirvfp);
+           afscp_FreeFid(newvfp); /* release now-unneeded fid */
+           newvfp = NULL;
+           if (code != 0) {
+               afs_com_err(pnp, code, "(is dir %s in AFS?)", dirName);
+               goto cleanup;
+           }
+       }
     }
-    if (!hosts[0]) {
-       fprintf(stderr,"AFS file not found: %s\n", fname);
-       return ENOENT;
+
+    if ( (newvfp != NULL) && (newvfp->fid.Vnode & 1) ) {
+       code = EISDIR;
+       afs_com_err(pnp, code, "(%s is a directory, not a file)", fname);
+       goto cleanup;
     }
-    cl = FindCell(cell);
-    gettimeofday (&starttime, &Timezone);
-    useHost = hosts[0];
-    RXConn = FindRXConnection(useHost, htons(AFSCONF_FILEPORT), 1,
-                             cl->sc, cl->scIndex);
-    if (!RXConn) {
-        fprintf(stderr,"rx_NewConnection failed to server 0x%X\n",
-               hosts[0]);
-        return -1;
+    gettimeofday(&starttime, &Timezone);
+
+    InStatus.UnixModeBits = 0644;
+    InStatus.Mask = AFS_SETMODE + AFS_FSYNC;
+    if (newvfp == NULL) {
+       code = afscp_CreateFile(dirvfp, baseName, &InStatus, &newvfp);
+       if (code != 0) {
+           afs_com_err(pnp, code,
+                       "(could not create file %s in directory %lu.%lu.%lu)",
+                       baseName, afs_printable_uint32_lu(dirvfp->fid.Volume),
+                       afs_printable_uint32_lu(dirvfp->fid.Vnode),
+                       afs_printable_uint32_lu(dirvfp->fid.Unique));
+           goto cleanup;
+       }
     }
-    code = AFS_FetchStatus(RXConn, &Fid, &OutStatus, &CallBack, &tsync);
-    if (code) {
-        fprintf(stderr,"RXAFS_FetchStatus failed to server 0x%X for file %s, code was%d\n",
-                            useHost, fname, code);
-       return -1;
+    code = afscp_GetStatus(newvfp, &OutStatus);
+    if (code != 0) {
+       afs_inet_ntoa_r(newvfp->cell->fsservers[0]->addrs[0], ipv4_addr);
+       afs_com_err(pnp, code, "(failed to get status of file %s from"
+                   "server %s, code = %d)", fname, ipv4_addr, code);
+       goto cleanup;
     }
-    if (!append && (OutStatus.Length || OutStatus.Length_hi)) {
-        fprintf(stderr,"AFS file %s not empty, request aborted.\n", fname);
-       DestroyConnections();
-        return -5;
+
+    if ( !append && !force &&
+        (OutStatus.Length != 0 || OutStatus.Length_hi !=0 ) ) {
+       /*
+        * file exists, is of non-zero length, and we're not appending
+        * to it: user must force overwrite
+        * (covers fidwrite edge case)
+        */
+       code = EEXIST;
+       afs_com_err(pnp, code, "(use -force to overwrite)");
+       goto cleanup;
     }
-    InStatus.Mask = AFS_SETMODE + AFS_FSYNC;
-    InStatus.UnixModeBits = 0644;
+
     if (append) {
        Pos = OutStatus.Length_hi;
        Pos = (Pos << 32) | OutStatus.Length;
     } else
-        Pos = 0;
+       Pos = 0;
     previous = (struct wbuf *)&bufchain;
     if (md5sum)
        MD5_Init(&md5);
 
+    /*
+     * currently, these two while loops (1) read the whole source file in
+     * before (2) writing any of it out, meaning that afsio can't deal with
+     * files larger than the maximum amount of memory designated for
+     * reading a file in (WRITEBUFLEN).
+     * Consider going to a single loop, like in readFile(), though will
+     * have implications on timing statistics (such as the "Startup to
+     * find the file" time, below).
+     */
     Len = 0;
-    while (Len<WRITEBUFFLEN) {
-       tbuf = (struct wbuf *)malloc(sizeof(struct wbuf));
-       if (!tbuf) {
+    while (Len < WRITEBUFLEN) {
+       tbuf = calloc(1, sizeof(struct wbuf));
+       if (tbuf == NULL) {
            if (!bufchain) {
-               fprintf(stderr, "Couldn't allocate buffer, aborting\n");
-               exit(1);
+               code = ENOMEM;
+               afs_com_err(pnp, code, "(cannot allocate buffer)");
+               goto cleanup;
            }
            break;
        }
-       memset(tbuf, 0, sizeof(struct wbuf));
        tbuf->buflen = BUFFLEN;
        if (synthesize) {
            afs_int64 ll, l = tbuf->buflen;
            if (l > synthlength)
                l = synthlength;
            for (ll = 0; ll < l; ll += 4096) {
-                sprintf(&tbuf->buf[ll],"Offset (0x%x, 0x%x)\n",
+               sprintf(&tbuf->buf[ll], "Offset (0x%x, 0x%x)\n",
                        (unsigned int)((offset + ll) >> 32),
                        (unsigned int)((offset + ll) & 0xffffffff));
            }
            offset += l;
            synthlength -= l;
-           tbuf->used = (afs_int32)l;
+           tbuf->used = (afs_int32) l;
        } else
-           tbuf->used = read(0, &tbuf->buf, tbuf->buflen);
-       if (!tbuf->used) {
+           tbuf->used = read(0, &tbuf->buf, tbuf->buflen); /* from stdin */
+       if (tbuf->used == 0) {
            free(tbuf);
            break;
        }
@@ -1292,230 +1043,80 @@ writeFile(struct cmd_syndesc *as, void *unused)
        Len += tbuf->used;
     }
     gettimeofday(&opentime, &Timezone);
-    if (verbose) {
-        seconds = (float) (opentime.tv_sec + opentime.tv_usec *.000001
-           -starttime.tv_sec - starttime.tv_usec *.000001);
-        fprintf(stderr,"Startup to find the file took %.3f sec.\n",
-               seconds);
-    }
+    if (verbose)
+       fprintf(stderr, "Startup to find the file took %.3f sec.\n",
+               time_elapsed(&starttime, &opentime));
     bytes = Len;
     while (!code && bytes) {
-        afs_int32 code2;
-        Len = bytes;
-    restart:
-        tcall = rx_NewCall(RXConn);
-        code = StartAFS_StoreData64 (tcall, &Fid, &InStatus, Pos, Len, Pos+Len);
-        if (code == RXGEN_OPCODE) {
-           afs_uint32 tmpLen, tmpPos;
-           tmpPos = (afs_int32) Pos;
-           tmpLen = (afs_int32) Len;
-           if (Pos+Len > 0x7fffffff) {
-               fprintf(stderr,"AFS fileserver does not support files >= 2 GB\n");
-               return EFBIG;
-           }
-           code = StartAFS_StoreData (tcall, &Fid, &InStatus, tmpPos, tmpLen,
-                                      tmpPos+tmpLen);
-        }
-        if (code) {
-            fprintf(stderr, "StartRXAFS_StoreData had error code %d\n", code);
-           return code;
-        }
-        length = Len;
-       tbuf = bufchain;
+       Len = bytes;
+       length = Len;
        if (Len) {
-            for (tbuf= bufchain; tbuf; tbuf=tbuf->next) {
-               if (!tbuf->used)
+           for (tbuf = bufchain; tbuf; tbuf = tbuf->next) {
+               if (tbuf->used == 0)
                    break;
-               byteswritten = rx_Write(tcall, tbuf->buf, tbuf->used);
-               if (byteswritten != tbuf->used) {
+               byteswritten = afscp_PWrite(newvfp, tbuf->buf,
+                                           tbuf->used, Pos + xfered);
+               if (byteswritten != tbuf->used) {
                    fprintf(stderr,"Only %d instead of %" AFS_INT64_FMT " bytes transferred by rx_Write()\n", byteswritten, length);
                    fprintf(stderr, "At %" AFS_UINT64_FMT " bytes from the end\n", length);
-                   code = -4;
+                   code = -4;
                    break;
-               }
+               }
                xfered += tbuf->used;
-               gettimeofday(&now, &Timezone);
-               if (verbose)
+               if (verbose)
                    printDatarate();
-               length -= tbuf->used;
-            }
-       }
-        worstCode = code;
-        code = EndRXAFS_StoreData64 (tcall, &OutStatus, &tsync);
-       if (code) {
-           fprintf(stderr, "EndRXAFS_StoreData64 returned %d\n", code);
-            worstCode = code;
-        }
-        code2 = rx_Error(tcall);
-       if (code2) {
-           fprintf(stderr, "rx_Error returned %d\n", code2);
-            worstCode = code2;
-        }
-        code2 = rx_EndCall(tcall, localcode);
-       if (code2) {
-           fprintf(stderr, "rx_EndCall returned %d\n", code2);
-            worstCode = code2;
-        }
-       code = worstCode;
-       if (code == 110) {
-           fprintf(stderr, "Waiting for busy volume\n");
-           sleep(10);
-           goto restart;
+               length -= tbuf->used;
+           }
        }
        Pos += Len;
        bytes = 0;
        if (!code) {
-            for (tbuf = bufchain; tbuf; tbuf=tbuf->next) {
-               tbuf->offset = 0;
+           for (tbuf = bufchain; tbuf; tbuf = tbuf->next) {
+               tbuf->offset = 0;
                if (synthesize) {
-                   afs_int64 ll, l = tbuf->buflen;
-                   if (l > synthlength)
+                   afs_int64 ll, l = tbuf->buflen;
+                   if (l > synthlength)
                        l = synthlength;
-                   for (ll = 0; ll < l; ll += 4096) {
-                       sprintf(&tbuf->buf[ll],"Offset (0x%x, 0x%x)\n",
+                   for (ll = 0; ll < l; ll += 4096) {
+                       sprintf(&tbuf->buf[ll], "Offset (0x%x, 0x%x)\n",
                                (unsigned int)((offset + ll) >> 32),
                                (unsigned int)((offset + ll) & 0xffffffff));
-                   }
-                   offset += l;
-                   synthlength -= l;
-                   tbuf->used = (afs_int32) l;
+                   }
+                   offset += l;
+                   synthlength -= l;
+                   tbuf->used = (afs_int32) l;
                } else
-                   tbuf->used = read(0, &tbuf->buf, tbuf->buflen);
-               if (!tbuf->used)
-                   break;
+                   tbuf->used = read(0, &tbuf->buf, tbuf->buflen); /* from stdin */
+               if (!tbuf->used)
+                   break;
                if (md5sum)
-                   MD5_Update(&md5, &tbuf->buf, tbuf->used);
-               Len += tbuf->used;
+                   MD5_Update(&md5, &tbuf->buf, tbuf->used);
+               Len += tbuf->used;
                bytes += tbuf->used;
-            }
-        }
+           }
+       }
     }
+
     gettimeofday(&writetime, &Timezone);
-    if (worstCode) {
-       fprintf(stderr,"%s failed with code %d\n", as->name, worstCode);
-    } else if(verbose) {
-        seconds = (float) (writetime.tv_sec + writetime.tv_usec *.000001
-           -opentime.tv_sec - opentime.tv_usec *.000001);
-        fprintf(stderr,"Transfer of %llu bytes took %.3f sec.\n",
-               xfered, seconds);
-        datarate = (xfered >> 20) / seconds;
-        fprintf(stderr,"Total data rate = %.03f MB/sec. for write\n",
-               datarate);
+    if (code) {
+       afs_com_err(pnp, code, "(%s failed with code %d)", as->name,
+                   code);
+    } else if (verbose) {
+       summarizeDatarate(&writetime, "write");
     }
     while (bufchain) {
        tbuf = bufchain;
        bufchain = tbuf->next;
        free(tbuf);
     }
-    DestroyConnections();
-    if (md5sum) {
-       afs_uint32 md5int[4];
-       char *p;
-       MD5_Final((char *) &md5int[0], &md5);
-#ifdef AFS_NT40_ENV
-        p = strrchr(fname,'\\');
-#else
-        p = strrchr(fname,'/');
-#endif
-        if (p)
-            p++;
-       else
-            p = fname;
 
-        fprintf(stderr, "%08x%08x%08x%08x  %s\n",
-               htonl(md5int[0]), htonl(md5int[1]),
-               htonl(md5int[2]), htonl(md5int[3]), p);
-    }
-    return worstCode;
-}
-
-struct cellLookup *
-FindCell(char *cellName)
-{
-    char name[MAXCELLCHARS];
-    char *np;
-    struct cellLookup *p, *p2;
-    static struct afsconf_dir *tdir;
-    time_t expires;
-    afs_int32 len, code;
-
-    if (cellName) {
-       np = cellName;
-    } else {
-        if (!tdir)
-           tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
-       len = MAXCELLCHARS;
-       afsconf_GetLocalCell(tdir, name, len);
-       np = (char *) &name;
-    }
-    SetCellFname(np);
-
-    p2 = (struct cellLookup *) &Cells;
-    for (p = Cells; p; p = p->next) {
-       if (!strcmp((char *)&p->info.name, np)) {
-#ifdef NO_AFS_CLIENT
-           if (!strcmp((char *)&lastcell, np))
-               code = VLDBInit(1, &p->info);
-#endif
-           return p;
-       }
-       p2 = p;
-    }
-    p2->next = (struct cellLookup *) malloc(sizeof(struct cellLookup));
-    p = p2->next;
-    memset(p, 0, sizeof(struct cellLookup));
-    p->next = (struct cellLookup *) 0;
-    if (!tdir)
-       tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
-    if (afsconf_GetCellInfo(tdir, np, AFSCONF_VLDBSERVICE, &p->info)) {
-       p2->next = (struct cellLookup *) 0;
-       free(p);
-       p = (struct cellLookup *) 0;
-    } else {
-#ifdef NO_AFS_CLIENT
-       if (code = VLDBInit(1, &p->info))
-            fprintf(stderr,"VLDBInit failed for cell %s\n", p->info.name);
-#endif
-       code = afsconf_ClientAuthToken(&p->info, 0, &p->sc, &p->scIndex, &expires);
-       if (code) {
-           p->scIndex = RX_SECIDX_NULL;
-            p->sc = rxnull_NewClientSecurityObject();
-       }
-    }
-
-    if (p)
-        return p;
-    else
-       return 0;
-}
-
-struct rx_connection *
-FindRXConnection(afs_uint32 host, u_short port, u_short service,
-                struct rx_securityClass *securityObject,
-                int serviceSecurityIndex)
-{
-    int i;
-
-    if (!ConnLookupInitialized) {
-       memset(ConnLookup, 0, MAX_HOSTS * sizeof(struct connectionLookup));
-       ConnLookupInitialized = 1;
-    }
-
-    for (i = 0; i < MAX_HOSTS; i++) {
-        if ((ConnLookup[i].host == host) && (ConnLookup[i].port == port))
-           return ConnLookup[i].conn;
-       if (!ConnLookup[i].conn)
-           break;
-    }
-
-    if (i >= MAX_HOSTS)
-       return 0;
-
-    ConnLookup[i].conn = rx_NewConnection(host, port, service, securityObject, serviceSecurityIndex);
-    if (ConnLookup[i].conn) {
-       ConnLookup[i].host = host;
-       ConnLookup[i].port = port;
-    }
+    if (md5sum)
+       summarizeMD5(fname);
 
-    return ConnLookup[i].conn;
-}
+cleanup:
+    free(baseName);
+    free(dirName);
+    afscp_FreeFid(newvfp);
+    afscp_FreeFid(dirvfp);
+    return code;
+} /* writeFile */