afsio: add -clear and -crypt option
[openafs.git] / src / venus / afsio.c
index 41d7778..5bdc787 100644 (file)
 
 #include <roken.h>
 
-#include <stdio.h>
 #ifdef AFS_NT40_ENV
 #include <windows.h>
 #define _CRT_RAND_S
-#include <process.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 <netdb.h>
 #include <afs/afsint.h>
 #define FSINT_COMMON_XG 1
 #endif
-#include <sys/stat.h>
+
+#include <afs/opr.h>
 #include <afs/cmd.h>
 #include <afs/auth.h>
 #include <afs/vlserver.h>
 #include <afs/ihandle.h>
 #include <afs/com_err.h>
 #include <afs/afscp.h>
-#ifdef HAVE_DIRENT_H
-#include <dirent.h>
-#endif
+
 #ifdef HAVE_DIRECT_H
 #include <direct.h>
 #endif
-#ifdef AFS_DARWIN_ENV
-#include <sys/malloc.h>
-#else
-#include <malloc.h>
-#endif
 #include <hcrypto/md5.h>
 #ifdef AFS_PTHREAD_ENV
-#include <assert.h>
 pthread_key_t uclient_key;
 #endif
 
+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);
@@ -84,12 +75,16 @@ static int CmdProlog(struct cmd_syndesc *, 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 int BreakUpPath(char *, char *, char *, size_t);
 
 static char pnp[AFSPATHMAX];   /* filename of this program when called */
 static int verbose = 0;                /* Set if -verbose option given */
+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;
@@ -228,6 +223,10 @@ CmdProlog(struct cmd_syndesc *as, char **cellp, char **realmp,
        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) {
@@ -243,6 +242,10 @@ CmdProlog(struct cmd_syndesc *as, char **cellp, char **realmp,
                *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;
@@ -251,25 +254,76 @@ CmdProlog(struct cmd_syndesc *as, char **cellp, char **realmp,
 int
 main(int argc, char **argv)
 {
-    afs_int32 code = 0;
     struct cmd_syndesc *ts;
     char baseName[AFSNAMEMAX];
 
     /* try to get only the base name of this executable for use in logs */
-    if (BreakUpPath(argv[0], NULL, baseName) > 0)
+    if (BreakUpPath(argv[0], NULL, baseName, AFSNAMEMAX) > 0)
        strlcpy(pnp, baseName, AFSNAMEMAX);
     else
        strlcpy(pnp, argv[0], AFSPATHMAX);
 
 #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,
+                         "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,
+                         "lock by FID a file from AFS");
+    cmd_IsAdministratorCommand(ts);
+    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,
+                         "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,
+                         "unlock by FID a file from AFS");
+    cmd_IsAdministratorCommand(ts);
+    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,
                          "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, "-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");
 
@@ -280,14 +334,17 @@ main(int argc, char **argv)
                "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, "-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,
                          "write a file into 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_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
                "overwrite existing file");
@@ -302,31 +359,37 @@ main(int argc, char **argv)
                "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_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,
                          "append to 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_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
 
-    ts = cmd_CreateSyntax("fidappend", writeFile, CMD_REQUIRED,
+    ts = cmd_CreateSyntax("fidappend", writeFile, NULL,
                          "append to a file in AFS");
     cmd_IsAdministratorCommand(ts);
     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, "-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");
 
     if (afscp_Init(NULL) != 0)
        exit(1);
 
-    code = cmd_Dispatch(argc, argv);
+    cmd_Dispatch(argc, argv);
 
     afscp_Finalize();
     exit(0);
@@ -392,13 +455,12 @@ GetVenusFidByFid(char *fidString, char *cellName, int onlyRW,
     struct afscp_volume *avolp;
 
     if (*avfpp == NULL) {
-       *avfpp = malloc(sizeof(struct afscp_venusfid));
+       *avfpp = calloc(1, sizeof(struct afscp_venusfid));
        if ( *avfpp == NULL ) {
            code = ENOMEM;
            return code;
        }
     }
-    memset(*avfpp, 0, sizeof(struct afscp_venusfid));
 
     if (cellName == NULL) {
        (*avfpp)->cell = afscp_DefaultCell();
@@ -471,7 +533,7 @@ GetVenusFidByFid(char *fidString, char *cellName, int onlyRW,
  *       2 if both dirName and baseName were filled in
  */
 static int
-BreakUpPath(char *fullPath, char *dirName, char *baseName)
+BreakUpPath(char *fullPath, char *dirName, char *baseName, size_t baseNameSize)
 {
     char *lastSlash;
     size_t dirNameLen = 0;
@@ -498,18 +560,18 @@ BreakUpPath(char *fullPath, char *dirName, char *baseName)
        /* then lastSlash points to the last path separator in fullPath */
        if (useDirName) {
            dirNameLen = strlen(fullPath) - strlen(lastSlash);
-           strlcpy(dirName, fullPath, dirNameLen + 1);
+           strlcpy(dirName, fullPath, min(dirNameLen + 1, baseNameSize));
            code++;
        }
        if (useBaseName) {
            lastSlash++;
-           strlcpy(baseName, lastSlash, strlen(lastSlash) + 1);
+           strlcpy(baseName, lastSlash, min(strlen(lastSlash) + 1, baseNameSize));
            code++;
        }
     } else {
        /* there are no path separators in fullPath -- it's just a baseName */
        if (useBaseName) {
-           strlcpy(baseName, fullPath, strlen(fullPath) + 1);
+           strlcpy(baseName, fullPath, min(strlen(fullPath) + 1, baseNameSize));
            code++;
        }
     }
@@ -558,6 +620,89 @@ GetVenusFidByPath(char *fullPath, char *cellName,
 } /* GetVenusFidByPath */
 
 static int
+lockFile(struct cmd_syndesc *as, void *arock)
+{
+    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;
+
+#ifdef AFS_NT40_ENV
+    /* stdout on Windows defaults to _O_TEXT mode */
+    _setmode(1, _O_BINARY);
+#endif
+
+    gettimeofday(&starttime, &Timezone);
+
+    CmdProlog(as, &cell, &realm, &fname, NULL);
+    afscp_AnonymousAuth(1);
+    if (clear)
+       afscp_Insecure();
+
+    if ((locktype == LockWrite) && readlock)
+       locktype = LockRead;
+
+    if (realm != NULL)
+       code = afscp_SetDefaultRealm(realm);
+
+    if (cell != NULL)
+       code = afscp_SetDefaultCell(cell);
+
+    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);
+       return code;
+    }
+
+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;
+    }
+
+    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;
+       }
+    } else {
+       if (OutStatus.lockCount == 0) {
+           code = -1;
+       }
+    }
+
+    if (!code) {
+       code = afscp_Lock(avfp, locktype);
+       if ((code == -1) && (afscp_errno == EWOULDBLOCK))
+           goto retry;
+    }
+    afscp_FreeFid(avfp);
+
+    if (buf != NULL)
+       free(buf);
+
+    if (code != 0)
+       afs_com_err(pnp, code, "(failed to change lock status: %d)", afscp_errno);
+
+    return code;
+} /* lockFile */
+
+static int
 readFile(struct cmd_syndesc *as, void *unused)
 {
     char *fname = NULL;
@@ -584,6 +729,8 @@ readFile(struct cmd_syndesc *as, void *unused)
 
     CmdProlog(as, &cell, &realm, &fname, NULL);
     afscp_AnonymousAuth(1);
+    if (clear)
+       afscp_Insecure();
 
     if (md5sum)
        MD5_Init(&md5);
@@ -627,14 +774,13 @@ readFile(struct cmd_syndesc *as, void *unused)
     Len <<= 32;
     Len += OutStatus.Length;
     ZeroInt64(Pos);
-    buf = (char *) malloc(bufflen * sizeof(char));
+    buf = calloc(bufflen, sizeof(char));
     if (buf == NULL) {
        code = ENOMEM;
        afs_com_err(pnp, code, "(cannot allocate buffer)");
        afscp_FreeFid(avfp);
        return code;
     }
-    memset(buf, 0, bufflen * sizeof(char));
     length = Len;
     while (!code && NonZeroInt64(length)) {
        if (length > bufflen)
@@ -702,6 +848,8 @@ writeFile(struct cmd_syndesc *as, void *unused)
 
     CmdProlog(as, &cell, &realm, &fname, &sSynthLen);
     afscp_AnonymousAuth(1);
+    if (clear)
+       afscp_Insecure();
 
     if (realm != NULL)
        code = afscp_SetDefaultRealm(realm);
@@ -748,7 +896,7 @@ writeFile(struct cmd_syndesc *as, void *unused)
            }
        }
        if (!append && !overWrite) { /* must create a new file in this case */
-           if ( BreakUpPath(fname, dirName, baseName) != 2 ) {
+           if ( BreakUpPath(fname, dirName, baseName, AFSNAMEMAX) != 2 ) {
                code = EINVAL;
                afs_com_err(pnp, code, "(must provide full AFS path)");
                afscp_FreeFid(newvfp);
@@ -775,6 +923,7 @@ writeFile(struct cmd_syndesc *as, void *unused)
     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) {
@@ -810,7 +959,6 @@ writeFile(struct cmd_syndesc *as, void *unused)
        return code;
     }
 
-    InStatus.Mask = AFS_SETMODE + AFS_FSYNC;
     if (append) {
        Pos = OutStatus.Length_hi;
        Pos = (Pos << 32) | OutStatus.Length;
@@ -831,7 +979,7 @@ writeFile(struct cmd_syndesc *as, void *unused)
      */
     Len = 0;
     while (Len < WRITEBUFLEN) {
-       tbuf = (struct wbuf *)malloc(sizeof(struct wbuf));
+       tbuf = calloc(1, sizeof(struct wbuf));
        if (tbuf == NULL) {
            if (!bufchain) {
                code = ENOMEM;
@@ -842,7 +990,6 @@ writeFile(struct cmd_syndesc *as, void *unused)
            }
            break;
        }
-       memset(tbuf, 0, sizeof(struct wbuf));
        tbuf->buflen = BUFFLEN;
        if (synthesize) {
            afs_int64 ll, l = tbuf->buflen;