libafscp: add lock support
authorDerrick Brashear <shadow@dementia.org>
Fri, 15 Apr 2011 17:45:57 +0000 (13:45 -0400)
committerDerrick Brashear <shadow@dementia.org>
Tue, 19 Apr 2011 15:08:38 +0000 (08:08 -0700)
add support for locking as well as for tracking callbacks so a
lock break can be detected

Change-Id: Iff36c6528fc55cf250bc27d49af80123d7ecece3
Reviewed-on: http://gerrit.openafs.org/4476
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Tested-by: Derrick Brashear <shadow@dementia.org>

src/libafscp/afscp.h
src/libafscp/afscp_callback.c
src/libafscp/afscp_dir.c
src/libafscp/afscp_dirops.c
src/libafscp/afscp_fid.c
src/libafscp/afscp_server.c
src/venus/afsio.c

index b9cc428..cd7fc9e 100644 (file)
@@ -9,6 +9,11 @@
 #include <afs/dir.h>
 #include <afs/afsutil.h>
 
+#ifdef AFS_NT40_ENV
+/* not included elsewhere for Windows */
+#include <pthread.h>
+#endif
+
 struct afscp_server {
     afsUUID id;
     int index;
@@ -69,11 +74,18 @@ struct afscp_dircache {
     int buflen;
     char *dirbuffer;
     int dv;
+    int nwaiters;
+    pthread_mutex_t mtx;
+    pthread_cond_t cv;
 };
 
 struct afscp_statent {
     struct afscp_venusfid me;
     struct AFSFetchStatus status;
+    int nwaiters;
+    int cleanup;
+    pthread_mutex_t mtx;
+    pthread_cond_t cv;
 };
 
 struct afscp_openfile {
@@ -112,6 +124,12 @@ struct afscp_server *afscp_ServerByIndex(int);
 struct rx_connection *afscp_ServerConnection(const struct afscp_server *,
                                             int);
 
+int afscp_CheckCallBack(const struct afscp_venusfid *fid,
+                       const struct afscp_server *server,
+                       afs_uint32 *expiretime);
+int afscp_FindCallBack(const struct afscp_venusfid *f,
+                      const struct afscp_server *server,
+                      struct afscp_callback *ret);
 int afscp_AddCallBack(const struct afscp_server *,
                      const struct AFSFid *,
                      const struct AFSFetchStatus *,
@@ -120,6 +138,7 @@ int afscp_RemoveCallBack(const struct afscp_server *,
                         const struct afscp_venusfid *);
 int afscp_ReturnCallBacks(const struct afscp_server *);
 int afscp_ReturnAllCallBacks(void);
+int afscp_WaitForCallback(const struct afscp_venusfid *fid, int seconds);
 
 /* file metastuff */
 /* frees with free() */
@@ -146,6 +165,7 @@ int afscp_GetStatus(const struct afscp_venusfid *, struct AFSFetchStatus *);
 int afscp_StoreStatus(const struct afscp_venusfid *, struct AFSStoreStatus *);
 int afscp_CreateFile(const struct afscp_venusfid *, char *,
                     struct AFSStoreStatus *, struct afscp_venusfid **);
+int afscp_Lock(const struct afscp_venusfid *, int locktype);
 int afscp_MakeDir(const struct afscp_venusfid *, char *,
                  struct AFSStoreStatus *, struct afscp_venusfid **);
 int afscp_Symlink(const struct afscp_venusfid *, char *,
index b01c522..b5fde52 100644 (file)
@@ -99,6 +99,48 @@ init_afs_cb(void)
 }                              /* init_afs_cb */
 
 int
+afscp_FindCallBack(const struct afscp_venusfid *f, const struct afscp_server *server, struct afscp_callback *ret)
+{
+    int i;
+    struct afscp_callback *use = NULL, *cb;
+    time_t now;
+    struct afscp_venusfid fid;
+
+    ret = NULL;
+
+    time(&now);
+    for (i = 0; i < afscp_maxcallbacks; i++) {
+       cb = &allcallbacks[i];
+       if ((f->fid.Volume == cb->fid.Volume) &&
+           (f->fid.Vnode == cb->fid.Vnode) &&
+           (f->fid.Unique == cb->fid.Unique)) {
+           if (server && (cb->server != server))
+               continue;
+           use = cb;
+           break;
+       }
+    }
+    if (!use)
+       return -1;
+
+    if (use->cb.ExpirationTime + use->as_of < now) {
+       if (use->valid) {
+           fid.cell = afscp_CellById(use->server->cell);
+           memcpy(&fid.fid, &use->fid, sizeof(struct AFSFid));
+           _StatInvalidate(&fid);
+       }
+       use->valid = 0;
+    }
+
+    if (use->valid)
+       ret = use;
+    else
+       return -1;
+
+    return 0;
+}
+
+int
 afscp_AddCallBack(const struct afscp_server *server,
                  const struct AFSFid *fid,
                  const struct AFSFetchStatus *fst,
@@ -108,37 +150,36 @@ afscp_AddCallBack(const struct afscp_server *server,
     struct afscp_callback *use = NULL, *newlist;
     struct afscp_venusfid f;
     time_t now;
-
+    
     time(&now);
-
+    
     for (i = 0; i < afscp_maxcallbacks; i++) {
        if (allcallbacks[i].cb.ExpirationTime + allcallbacks[i].as_of < now) {
-           if (allcallbacks[i].valid) {
-               f.cell = afscp_CellById(allcallbacks[i].server->cell);
-               memcpy(&f.fid, &allcallbacks[i].fid, sizeof(struct AFSFid));
-               _StatInvalidate(&f);
-           }
-           allcallbacks[i].valid = 0;
-
-       }
-
-       if (allcallbacks[i].valid == 0)
-           use = &allcallbacks[i];
-       if ((allcallbacks[i].server == server) &&
-           (fid->Volume == allcallbacks[i].fid.Volume) &&
-           (fid->Vnode == allcallbacks[i].fid.Vnode) &&
-           (fid->Unique == allcallbacks[i].fid.Unique)) {
-           use = &allcallbacks[i];
-           break;
-       }
+            if (allcallbacks[i].valid) {
+                f.cell = afscp_CellById(allcallbacks[i].server->cell);
+                memcpy(&f.fid, &allcallbacks[i].fid, sizeof(struct AFSFid));
+                _StatInvalidate(&f);
+            }
+            allcallbacks[i].valid = 0;
+        }
+       
+        if (allcallbacks[i].valid == 0)
+            use = &allcallbacks[i];
+        if ((allcallbacks[i].server == server) &&
+            (fid->Volume == allcallbacks[i].fid.Volume) &&
+            (fid->Vnode == allcallbacks[i].fid.Vnode) &&
+            (fid->Unique == allcallbacks[i].fid.Unique)) {
+            use = &allcallbacks[i];
+            break;
+        }
     }
     if (use == NULL) {
-       if (afscp_maxcallbacks >= afscp_cballoced) {
-           if (afscp_cballoced != 0)
-               afscp_cballoced = afscp_cballoced * 2;
-           else
-               afscp_cballoced = 4;
-           newlist = realloc(allcallbacks, afscp_cballoced *
+        if (afscp_maxcallbacks >= afscp_cballoced) {
+            if (afscp_cballoced != 0)
+                afscp_cballoced = afscp_cballoced * 2;
+            else
+                afscp_cballoced = 4;
+            newlist = realloc(allcallbacks, afscp_cballoced *
                              sizeof(struct afscp_callback));
            if (newlist == NULL) {
                return -1;
index eb95c73..84af127 100644 (file)
@@ -104,7 +104,16 @@ _DirUpdate(struct afscp_dirstream *d)
            d->dv = stored->dv;
            return 0;
        }
+       pthread_mutex_lock(&(stored->mtx));
        tdelete(&key, &v->dircache, dircompare);
+       stored->nwaiters++;
+       while (stored->nwaiters > 1) {
+           pthread_cond_wait(&(stored->cv), &(stored->mtx));
+       }
+       stored->nwaiters--;
+       pthread_cond_destroy(&(stored->cv));
+       pthread_mutex_unlock(&(stored->mtx));
+       pthread_mutex_destroy(&(stored->mtx));
        if (d->dirbuffer != stored->dirbuffer)
            free(stored->dirbuffer);
        free(stored);
@@ -142,6 +151,9 @@ _DirUpdate(struct afscp_dirstream *d)
            stored->buflen = d->buflen;
            stored->dirbuffer = d->dirbuffer;
            stored->dv = d->dv;
+           stored->nwaiters = 0;
+           pthread_mutex_init(&(stored->mtx), NULL);
+           pthread_cond_init(&(stored->cv), NULL);
            *(struct afscp_dircache **)cached = stored;
        } else {
            tdelete(&key, &v->dircache, dircompare);
index 3fb08f8..238535c 100644 (file)
@@ -32,6 +32,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <afs/vlserver.h>
 #include <afs/vldbint.h>
 #include <afs/dir.h>
+#include <afs/unified_afs.h>
 #include "afscp.h"
 #include "afscp_internal.h"
 
@@ -189,6 +190,51 @@ afscp_Symlink(const struct afscp_venusfid *dir, char *name,
 
 
 int
+afscp_Lock(const struct afscp_venusfid *fid, int locktype)
+{
+    int code, i, j;
+    struct AFSFid ff = fid->fid;
+    struct afscp_volume *vol;
+    struct AFSVolSync vs;
+    struct afscp_server *server;
+    struct rx_connection *c;
+
+    vol = afscp_VolumeById(fid->cell, fid->fid.Volume);
+    if (vol == NULL) {
+       afscp_errno = ENOENT;
+       return -1;
+    }
+    code = ENOENT;
+    for (i = 0; i < vol->nservers; i++) {
+       server = afscp_ServerByIndex(vol->servers[i]);
+       if (server && server->naddrs > 0) {
+           for (j = 0; j < server->naddrs; j++) {
+               c = afscp_ServerConnection(server, j);
+               if (c == NULL)
+                   break;
+               if (locktype == LockRelease)
+                   code = RXAFS_ReleaseLock(c, &ff, &vs);
+               /* read, write, extend */
+               else if (locktype < LockRelease)
+                   code = RXAFS_SetLock(c, &ff, locktype, &vs);
+               if (code >= 0)
+                   break;
+           }
+       }
+       if (code >= 0)
+           break;
+    }
+    if (code != 0) {
+       if ((code == EAGAIN) || (code == UAEWOULDBLOCK) || (code == UAEAGAIN))
+           code = EWOULDBLOCK;
+       afscp_errno = code;
+       return -1;
+    }
+    return 0;
+}
+
+
+int
 afscp_RemoveFile(const struct afscp_venusfid *dir, char *name)
 {
     int code, i, j;
index 9d9183c..538381b 100644 (file)
@@ -102,6 +102,61 @@ statcompare(const void *a, const void *b)
     return 0;
 }
 
+static void
+_StatCleanup(struct afscp_statent *stored)
+{
+    pthread_cond_destroy(&(stored->cv));
+    pthread_mutex_unlock(&(stored->mtx));
+    pthread_mutex_destroy(&(stored->mtx));
+    free(stored);
+}
+
+int
+afscp_WaitForCallback(const struct afscp_venusfid *fid, int seconds)
+{
+    void **cached;
+    struct afscp_volume *v;
+    struct afscp_statent *stored, key;
+    int code = 0;
+
+    v = afscp_VolumeById(fid->cell, fid->fid.Volume);
+    if (v == NULL) {
+        return -1;
+    }
+    memmove(&key.me, fid, sizeof(*fid));
+
+    cached = tfind(&key, &v->statcache, statcompare);
+    if (cached != NULL) {
+        struct timeval tv;
+        struct timespec ts;
+
+        stored = *(struct afscp_statent **)cached;
+
+        if (seconds) {
+           gettimeofday(&tv, NULL);
+           ts.tv_sec = tv.tv_sec + seconds;
+           ts.tv_nsec = 0;
+       }
+
+        pthread_mutex_lock(&(stored->mtx));
+       stored->nwaiters++;
+       if (seconds)
+           code = pthread_cond_timedwait(&(stored->cv), &(stored->mtx), &ts);
+       else
+           pthread_cond_wait(&(stored->cv), &(stored->mtx));
+       if ((stored->nwaiters == 1) && stored->cleanup)
+           _StatCleanup(stored);
+       else
+           stored->nwaiters--;
+        pthread_mutex_unlock(&(stored->mtx));
+    }
+    if ((code == EINTR) || (code == ETIMEDOUT)) {
+       afscp_errno = code;
+       code = -1;
+    }      
+    return code;
+}
+
 int
 afscp_GetStatus(const struct afscp_venusfid *fid, struct AFSFetchStatus *s)
 {
@@ -125,10 +180,14 @@ afscp_GetStatus(const struct afscp_venusfid *fid, struct AFSFetchStatus *s)
     cached = tfind(&key, &v->statcache, statcompare);
     if (cached != NULL) {
        stored = *(struct afscp_statent **)cached;
+       pthread_mutex_lock(&(stored->mtx));
        memmove(s, &stored->status, sizeof(*s));
        afs_dprintf(("Stat %u.%lu.%lu.%lu returning cached result\n",
                     fid->cell->id, fid->fid.Volume, fid->fid.Vnode,
                     fid->fid.Unique));
+       if (stored->nwaiters)
+           pthread_cond_broadcast(&(stored->cv));
+       pthread_mutex_unlock(&(stored->mtx));
        return 0;
     }
 
@@ -201,10 +260,41 @@ afscp_Stat(const struct afscp_venusfid *fid, struct stat *s)
 }
 
 int
+afscp_CheckCallBack(const struct afscp_venusfid *fid, const struct afscp_server *server, afs_uint32 *expiretime)
+{
+    struct AFSFetchStatus status;
+    struct afscp_callback *cb = NULL;
+    int code;
+    time_t now;
+
+    if (expiretime == NULL || fid == NULL) {
+       fprintf(stderr, "NULL args given to afscp_CheckCallback, cannot continue\n");
+       return -1;
+    }
+
+    *expiretime = 0;
+
+    code = afscp_GetStatus(fid, &status);
+    if (code != 0)
+       return code;
+
+    code = afscp_FindCallBack(fid, server, cb);
+    if (code != 0)
+       return code;
+
+    if (cb) {
+       time(&now);
+       *expiretime = cb->cb.ExpirationTime + cb->as_of - now;
+    }
+
+    return 0;
+}
+
+int
 _StatInvalidate(const struct afscp_venusfid *fid)
 {
     struct afscp_volume *v;
-    struct afscp_statent key;
+    struct afscp_statent *stored, key;
     void **cached;
 
     v = afscp_VolumeById(fid->cell, fid->fid.Volume);
@@ -215,8 +305,16 @@ _StatInvalidate(const struct afscp_venusfid *fid)
 
     cached = tfind(&key, &v->statcache, statcompare);
     if (cached != NULL) {
-       free(*cached);
+        stored = *(struct afscp_statent **)cached;
+       pthread_mutex_lock(&(stored->mtx));
        tdelete(&key, &v->statcache, statcompare);
+       if (stored->nwaiters) {
+           /* avoid blocking callback thread */
+           pthread_cond_broadcast(&(stored->cv));
+           stored->cleanup = 1;
+       } else
+           _StatCleanup(stored);
+       pthread_mutex_unlock(&(stored->mtx));
     }
     return 0;
 }
@@ -238,6 +336,10 @@ _StatStuff(const struct afscp_venusfid *fid, const struct AFSFetchStatus *s)
     if (cached != NULL) {
        stored = malloc(sizeof(struct afscp_statent));
        if (stored != NULL) {
+           pthread_mutex_init(&(stored->mtx), NULL);
+           pthread_cond_init(&(stored->cv), NULL);
+           stored->nwaiters = 0;
+           stored->cleanup = 0;
            memmove(&stored->me, fid, sizeof(*fid));
            memmove(&stored->status, s, sizeof(*s));
            *(struct afscp_statent **)cached = stored;
index 2223d7b..84be5e8 100644 (file)
@@ -246,6 +246,7 @@ _xdr_bulkaddrs(XDR * xdrs, void *objp)
     return xdr_bulkaddrs(xdrs, objp);
 }
 
+/* takes server in host byte order */
 struct afscp_server *
 afscp_ServerById(struct afscp_cell *thecell, afsUUID * u)
 {
@@ -456,6 +457,7 @@ afscp_AnyServerByAddr(afs_uint32 addr)
     return NULL;
 }
 
+/* takes server in host byte order */
 struct afscp_server *
 afscp_ServerByIndex(int i)
 {
index 41d7778..f8387c9 100644 (file)
@@ -75,6 +75,7 @@
 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);
@@ -90,6 +91,8 @@ static char pnp[AFSPATHMAX];  /* filename of this program when called */
 static int verbose = 0;                /* Set if -verbose option given */
 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;
@@ -243,6 +246,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;
@@ -265,7 +272,49 @@ main(int argc, char **argv)
     assert(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_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_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_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_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");
@@ -283,7 +332,7 @@ main(int argc, char **argv)
     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");
@@ -307,14 +356,14 @@ main(int argc, char **argv)
                "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, "-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,
@@ -558,6 +607,87 @@ 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 ((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;
@@ -775,6 +905,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 +941,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;