vol: Blank fake linkHandles
[openafs.git] / src / vol / namei_ops.c
index 53622a6..463b66b 100644 (file)
 #ifdef AFS_SALSRV_ENV
 #include <pthread.h>
 #include <afs/work_queue.h>
-#include <afs/thread_pool.h>
 #include <vol/vol-salvage.h>
 #endif
 
 int Testing=0;
 
+static void namei_UnlockLinkCount(FdHandle_t * fdP, Inode ino);
 
 afs_sfsize_t
 namei_iread(IHandle_t * h, afs_foff_t offset, char *buf, afs_fsize_t size)
@@ -325,7 +325,7 @@ int
 namei_ViceREADME(char *partition)
 {
     char filename[32];
-    int fd;
+    int fd, len, e = 0;
 
     /* Create the inode directory if we're starting for the first time */
     snprintf(filename, sizeof filename, "%s" OS_DIRSEP "%s", partition,
@@ -337,8 +337,12 @@ namei_ViceREADME(char *partition)
              partition, INODEDIR);
     fd = OS_OPEN(filename, O_WRONLY | O_CREAT | O_TRUNC, 0444);
     if (fd != INVALID_FD) {
-       (void)OS_WRITE(fd, VICE_README, strlen(VICE_README));
+       len = strlen(VICE_README);
+       if (OS_WRITE(fd, VICE_README, len) != len)
+           e = errno;
        OS_CLOSE(fd);
+       if (e)
+           errno = e;
     }
     return (errno);
 }
@@ -599,7 +603,7 @@ namei_RemoveDataDirectories(namei_t * name)
  * types, but if we get that far, this could should be dead by then.
  */
 Inode
-namei_MakeSpecIno(int volid, int type)
+namei_MakeSpecIno(VolumeId volid, int type)
 {
     Inode ino;
     ino = NAMEI_INODESPECIAL;
@@ -834,6 +838,8 @@ namei_icreate(IHandle_t * lh, char *part, afs_uint32 p1, afs_uint32 p2, afs_uint
     memset((void *)&tmp, 0, sizeof(IHandle_t));
     memset(&tfd, 0, sizeof(FdHandle_t));
 
+    ih_PkgDefaults();
+
     tmp.ih_dev = nt_DriveToDev(part);
     if (tmp.ih_dev == -1) {
        errno = EINVAL;
@@ -952,20 +958,22 @@ bad:
 }
 #else /* !AFS_NT40_ENV */
 Inode
-namei_icreate(IHandle_t * lh, char *part, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4)
+icreate(IHandle_t * lh, char *part, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4,
+        IHandle_t **a_ih)
 {
     namei_t name;
     int fd = INVALID_FD;
     int code = 0;
     int created_dir = 0;
     IHandle_t tmp;
+    IHandle_t *realh = NULL;
     FdHandle_t *fdP;
-    FdHandle_t tfd;
     int tag;
     int ogm_parm;
 
     memset((void *)&tmp, 0, sizeof(IHandle_t));
-    memset(&tfd, 0, sizeof(FdHandle_t));
+
+    ih_PkgDefaults();
 
     tmp.ih_dev = volutil_GetPartitionID(part);
     if (tmp.ih_dev == -1) {
@@ -1033,19 +1041,20 @@ namei_icreate(IHandle_t * lh, char *part, afs_uint32 p1, afs_uint32 p2, afs_uint
        goto bad;
     }
 
+    IH_INIT(realh, tmp.ih_dev, tmp.ih_vid, tmp.ih_ino);
+    fdP = ih_attachfd(realh, fd);
+
+    /* ih_attachfd can only return NULL if we give it an invalid fd; our fd
+     * must be valid by this point. */
+    opr_Assert(fdP);
+
     if (p2 == (afs_uint32)-1 && p3 == VI_LINKTABLE) {
-       /* hack at tmp to setup for set link count call. */
-       memset((void *)&tfd, 0, sizeof(FdHandle_t));    /* minimalistic still, but a little cleaner */
-       tfd.fd_ih = &tmp;
-       tfd.fd_fd = fd;
-       code = namei_SetLinkCount(&tfd, (Inode) 0, 1, 0);
+       code = namei_SetLinkCount(fdP, (Inode) 0, 1, 0);
     }
 
-  bad:
-    if (fd != INVALID_FD)
-       OS_CLOSE(fd);
-
+    FDH_CLOSE(fdP);
 
+  bad:
     if (code || (fd == INVALID_FD)) {
        if (p2 != -1) {
            fdP = IH_OPEN(lh);
@@ -1054,8 +1063,45 @@ namei_icreate(IHandle_t * lh, char *part, afs_uint32 p1, afs_uint32 p2, afs_uint
                FDH_CLOSE(fdP);
            }
        }
+       IH_RELEASE(realh);
+    }
+
+    *a_ih = realh;
+
+    return code;
+}
+
+Inode
+namei_icreate(IHandle_t * lh, char *part,
+              afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4)
+{
+    Inode ino;
+    IHandle_t *ihP = NULL;
+    int code;
+
+    code = icreate(lh, part, p1, p2, p3, p4, &ihP);
+    if (code || !ihP) {
+       opr_Assert(!ihP);
+       ino = -1;
+    } else {
+       ino = ihP->ih_ino;
+       IH_RELEASE(ihP);
+    }
+    return ino;
+}
+
+IHandle_t *
+namei_icreate_init(IHandle_t * lh, int dev, char *part,
+                   afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4)
+{
+    int code;
+    IHandle_t *ihP = NULL;
+
+    code = icreate(lh, part, p1, p2, p3, p4, &ihP);
+    if (code) {
+       opr_Assert(!ihP);
     }
-    return (code || (fd == INVALID_FD)) ? (Inode) - 1 : tmp.ih_ino;
+    return ihP;
 }
 #endif
 
@@ -1116,20 +1162,34 @@ namei_dec(IHandle_t * ih, Inode ino, int p1)
            }
 
            count--;
-           if (namei_SetLinkCount(fdP, (Inode) 0, count < 0 ? 0 : count, 1) <
-               0) {
-               FDH_REALLYCLOSE(fdP);
-               IH_RELEASE(tmp);
-               return -1;
-           }
-
            if (count > 0) {
+               /* if our count is non-zero, we just set our new linkcount and
+                * return. But if our count is 0, don't bother updating the
+                * linktable, since we're about to delete the link table,
+                * below. */
+               if (namei_SetLinkCount(fdP, (Inode) 0, count < 0 ? 0 : count, 1) < 0) {
+                   FDH_REALLYCLOSE(fdP);
+                   IH_RELEASE(tmp);
+                   return -1;
+               }
+
                FDH_CLOSE(fdP);
                IH_RELEASE(tmp);
                return 0;
            }
+
+           namei_UnlockLinkCount(fdP, (Inode) 0);
        }
 
+       /* We should IH_REALLYCLOSE right before deleting the special file from
+        * disk, to ensure that somebody else cannot create a special inode,
+        * then IH_OPEN that special inode and get back a cached fd for the
+        * file we are deleting here (instead of an fd for the file they just
+        * created). */
+       IH_REALLYCLOSE(tmp);
+       FDH_REALLYCLOSE(fdP);
+       IH_RELEASE(tmp);
+
        if ((code = OS_UNLINK(name.n_path)) == 0) {
            if (type == VI_LINKTABLE) {
                /* Try to remove directory. If it fails, that's ok.
@@ -1143,8 +1203,6 @@ namei_dec(IHandle_t * ih, Inode ino, int p1)
                (void)namei_RemoveDataDirectories(&name);
            }
        }
-       FDH_REALLYCLOSE(fdP);
-       IH_RELEASE(tmp);
     } else {
        /* Get a file descriptor handle for this Inode */
        fdP = IH_OPEN(ih);
@@ -1166,8 +1224,8 @@ namei_dec(IHandle_t * ih, Inode ino, int p1)
        } else {
            IHandle_t *th;
            IH_INIT(th, ih->ih_dev, ih->ih_vid, ino);
-           Log("Warning: Lost ref on ihandle dev %d vid %d ino %lld\n",
-               th->ih_dev, th->ih_vid, (afs_int64)th->ih_ino);
+           Log("Warning: Lost ref on ihandle dev %d vid %" AFS_VOLID_FMT " ino %lld\n",
+               th->ih_dev, afs_printable_VolumeId_lu(th->ih_vid), (afs_int64)th->ih_ino);
            IH_RELEASE(th);
 
            /* If we're less than 0, someone presumably unlinked;
@@ -1262,7 +1320,7 @@ namei_copy_on_write(IHandle_t *h)
     if (afs_stat(name.n_path, &tstat) < 0)
        return EIO;
     if (tstat.st_nlink > 1) {                   /* do a copy on write */
-       char path[259];
+       char path[NAMEI_PATH_LEN + 4];
        char *buf;
        afs_size_t size;
        ssize_t tlen;
@@ -1517,7 +1575,10 @@ namei_GetLinkCount(FdHandle_t * h, Inode ino, int lockit, int fixup, int nowrite
            NAMEI_GLC_UNLOCK;
            goto bad_getLinkByte;
        }
-        FDH_TRUNC(h, offset+sizeof(row));
+        if (FDH_TRUNC(h, offset+sizeof(row))) {
+           NAMEI_GLC_UNLOCK;
+           goto bad_getLinkByte;
+       }
         row = 1 << index;
        rc = FDH_PWRITE(h, (char *)&row, sizeof(row), offset);
        NAMEI_GLC_UNLOCK;
@@ -1552,12 +1613,6 @@ namei_GetLinkCount(FdHandle_t * h, Inode ino, int lockit, int fixup, int nowrite
     return -1;
 }
 
-int
-namei_SetNonZLC(FdHandle_t * h, Inode ino)
-{
-    return namei_GetLinkCount(h, ino, 0, 1, 0);
-}
-
 /* Return a free column index for this vnode. */
 static int
 GetFreeTag(IHandle_t * ih, int vno)
@@ -1574,14 +1629,14 @@ GetFreeTag(IHandle_t * ih, int vno)
     if (fdP == NULL)
        return -1;
 
+    offset = (vno << LINKTABLE_SHIFT) + 8;     /* * 2 + sizeof stamp */
+
     /* Only one manipulates at a time. */
     if (FDH_LOCKFILE(fdP, offset) != 0) {
        FDH_REALLYCLOSE(fdP);
        return -1;
     }
 
-    offset = (vno << LINKTABLE_SHIFT) + 8;     /* * 2 + sizeof stamp */
-
     nBytes = FDH_PREAD(fdP, (char *)&row, sizeof(row), offset);
     if (nBytes != sizeof(row)) {
        if (nBytes != 0)
@@ -1670,18 +1725,29 @@ namei_SetLinkCount(FdHandle_t * fdP, Inode ino, int count, int locked)
     return (int)nBytes;
 }
 
+static void
+namei_UnlockLinkCount(FdHandle_t * fdP, Inode ino)
+{
+    afs_foff_t offset;
+    int index;
+
+    namei_GetLCOffsetAndIndexFromIno(ino, &offset, &index);
+
+    FDH_UNLOCKFILE(fdP, offset);
+}
+
 
 /* ListViceInodes - write inode data to a results file. */
 static int DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
-                      unsigned int volid);
-static int DecodeVolumeName(char *name, unsigned int *vid);
+                      IHandle_t *myIH);
+static int DecodeVolumeName(char *name, VolumeId *vid);
 static int namei_ListAFSSubDirs(IHandle_t * dirIH,
                                int (*write_fun) (FD_t,
                                                  struct ViceInodeInfo *,
                                                  char *, char *), FD_t fp,
                                int (*judgeFun) (struct ViceInodeInfo *,
-                                                afs_uint32 vid, void *),
-                               afs_uint32 singleVolumeNumber, void *rock);
+                                                VolumeId vid, void *),
+                               VolumeId singleVolumeNumber, void *rock);
 
 
 /* WriteInodeInfo
@@ -1745,8 +1811,8 @@ VerifyDirPerms(char *path)
  */
 int
 ListViceInodes(char *devname, char *mountedOn, FD_t inodeFile,
-              int (*judgeInode) (struct ViceInodeInfo * info, afs_uint32 vid, void *rock),
-              afs_uint32 singleVolumeNumber, int *forcep, int forceR, char *wpath,
+              int (*judgeInode) (struct ViceInodeInfo * info, VolumeId vid, void *rock),
+              VolumeId singleVolumeNumber, int *forcep, int forceR, char *wpath,
               void *rock)
 {
     int ninodes;
@@ -1812,8 +1878,8 @@ namei_ListAFSFiles(char *dev,
                   int (*writeFun) (FD_t, struct ViceInodeInfo *, char *,
                                    char *),
                   FD_t fp,
-                  int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *),
-                  afs_uint32 singleVolumeNumber, void *rock)
+                  int (*judgeFun) (struct ViceInodeInfo *, VolumeId, void *),
+                  VolumeId singleVolumeNumber, void *rock)
 {
     IHandle_t ih;
     namei_t name;
@@ -1929,14 +1995,14 @@ _namei_examine_special(char * path1,
                       int (*writeFun) (FD_t, struct ViceInodeInfo *, char *,
                                        char *),
                       FD_t fp,
-                      int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *),
-                      int singleVolumeNumber,
+                      int (*judgeFun) (struct ViceInodeInfo *, VolumeId, void *),
+                      VolumeId singleVolumeNumber,
                       void *rock)
 {
     int ret = 0;
     struct ViceInodeInfo info;
 
-    if (DecodeInode(path1, dname, &info, myIH->ih_vid) < 0) {
+    if (DecodeInode(path1, dname, &info, myIH) < 0) {
        ret = 0;
        goto error;
     }
@@ -1948,9 +2014,14 @@ _namei_examine_special(char * path1,
         * consistent with VGID encoded in namei path */
        Log("namei_ListAFSSubDirs: warning: inconsistent linktable "
            "filename \"%s" OS_DIRSEP "%s\"; salvager will delete it "
-           "(dir_vgid=%u, inode_vgid=%u)\n",
-           path1, dname, myIH->ih_vid,
-           info.u.param[0]);
+           "(dir_vgid=%" AFS_VOLID_FMT ", inode_vgid=%" AFS_VOLID_FMT ")\n",
+           path1, dname, afs_printable_VolumeId_lu(myIH->ih_vid),
+           afs_printable_VolumeId_lu(info.u.param[0]));
+       /* We need to set the linkCount to _something_, so linkCount
+        * doesn't just contain stack garbage. Set it to 0, so in case
+        * the salvager or whatever our caller is does try to process
+        * this like a normal file, we won't try to INC or DEC it. */
+       info.linkCount = 0;
     } else {
        char path2[512];
        /* Open this handle */
@@ -2012,8 +2083,8 @@ _namei_examine_reg(char * path3,
                   int (*writeFun) (FD_t, struct ViceInodeInfo *, char *,
                                    char *),
                   FD_t fp,
-                  int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *),
-                  int singleVolumeNumber,
+                  int (*judgeFun) (struct ViceInodeInfo *, VolumeId, void *),
+                  VolumeId singleVolumeNumber,
                   void *rock)
 {
     int ret = 0;
@@ -2022,7 +2093,7 @@ _namei_examine_reg(char * path3,
     int dirl; /* Windows-only (one level hash dir) */
 #endif
 
-    if (DecodeInode(path3, dname, &info, myIH->ih_vid) < 0) {
+    if (DecodeInode(path3, dname, &info, myIH) < 0) {
        goto error;
     }
 
@@ -2083,8 +2154,8 @@ struct listsubdirs_work_node {
     int (*writeFun) (FD_t, struct ViceInodeInfo *, char *, char *);
 
     /** inode filter function */
-    int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *);
-    int singleVolumeNumber;             /**< volume id filter */
+    int (*judgeFun) (struct ViceInodeInfo *, VolumeId, void *);
+    VolumeId singleVolumeNumber;             /**< volume id filter */
     void * rock;                        /**< pointer passed to writeFun and judgeFun */
     int code;                           /**< return code from examine function */
     int special;                        /**< asserted when this is a volume
@@ -2410,8 +2481,8 @@ namei_ListAFSSubDirs(IHandle_t * dirIH,
                     int (*writeFun) (FD_t, struct ViceInodeInfo *, char *,
                                      char *),
                     FD_t fp,
-                    int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *),
-                    afs_uint32 singleVolumeNumber, void *rock)
+                    int (*judgeFun) (struct ViceInodeInfo *, VolumeId, void *),
+                    VolumeId singleVolumeNumber, void *rock)
 {
     int code = 0, ret = 0;
     IHandle_t myIH = *dirIH;
@@ -2434,6 +2505,8 @@ namei_ListAFSSubDirs(IHandle_t * dirIH,
     struct rx_queue resultlist;
 #endif
 
+    memset(&linkHandle, 0, sizeof(linkHandle));
+
     namei_HandleToVolDir(&name, &myIH);
     strlcpy(path1, name.n_path, sizeof(path1));
 
@@ -2515,8 +2588,8 @@ namei_ListAFSSubDirs(IHandle_t * dirIH,
 #endif
 
     if (linkHandle.fd_fd == INVALID_FD) {
-       Log("namei_ListAFSSubDirs: warning: VG %u does not have a link table; "
-           "salvager will recreate it.\n", dirIH->ih_vid);
+       Log("namei_ListAFSSubDirs: warning: VG %" AFS_VOLID_FMT " does not have a link table; "
+           "salvager will recreate it.\n", afs_printable_VolumeId_lu(dirIH->ih_vid));
     }
 
     /* Now run through all the other subdirs */
@@ -2537,8 +2610,14 @@ namei_ListAFSSubDirs(IHandle_t * dirIH,
 
 #ifndef AFS_NT40_ENV /* This level missing on Windows */
            /* Now we've got a next level subdir. */
-           snprintf(path2, sizeof(path2), "%s" OS_DIRSEP "%s",
-                    path1, dp1->d_name);
+           code = snprintf(path2, sizeof(path2), "%s" OS_DIRSEP "%s",
+                           path1, dp1->d_name);
+           if (code < 0 || code >= sizeof(path2)) {
+               /* error, or truncated */
+               closedir(dirp1);
+               ret = -1;
+               goto error;
+           }
            dirp2 = opendir(path2);
            if (dirp2) {
                while ((dp2 = readdir(dirp2))) {
@@ -2546,13 +2625,22 @@ namei_ListAFSSubDirs(IHandle_t * dirIH,
                        continue;
 
                    /* Now we've got to the actual data */
-                   snprintf(path3, sizeof(path3), "%s" OS_DIRSEP "%s",
-                            path2, dp2->d_name);
+                   code = snprintf(path3, sizeof(path3), "%s" OS_DIRSEP "%s",
+                                   path2, dp2->d_name);
 #else
                    /* Now we've got to the actual data */
-                   snprintf(path3, sizeof(path3), "%s" OS_DIRSEP "%s",
-                            path1, dp1->d_name);
+                   code = snprintf(path3, sizeof(path3), "%s" OS_DIRSEP "%s",
+                                   path1, dp1->d_name);
 #endif
+                   if (code < 0 || code >= sizeof(path3)) {
+                       /* error, or truncated */
+#ifndef AFS_NT40_ENV
+                       closedir(dirp2);
+#endif
+                       closedir(dirp1);
+                       ret = -1;
+                       goto error;
+                   }
                    dirp3 = opendir(path3);
                    if (dirp3) {
                        while ((dp3 = readdir(dirp3))) {
@@ -2643,7 +2731,7 @@ namei_ListAFSSubDirs(IHandle_t * dirIH,
 
 #ifdef AFS_NT40_ENV
 static int
-DecodeVolumeName(char *name, unsigned int *vid)
+DecodeVolumeName(char *name, VolumeId *vid)
 {
     /* Name begins with "Vol_" and ends with .data.  See nt_HandleToVolDir() */
     char stmp[32];
@@ -2663,7 +2751,7 @@ DecodeVolumeName(char *name, unsigned int *vid)
 }
 #else
 static int
-DecodeVolumeName(char *name, unsigned int *vid)
+DecodeVolumeName(char *name, VolumeId *vid)
 {
     if (strlen(name) < 1)
        return -1;
@@ -2681,7 +2769,7 @@ DecodeVolumeName(char *name, unsigned int *vid)
 #ifdef AFS_NT40_ENV
 static int
 DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
-           unsigned int volid)
+           IHandle_t *myIH)
 {
     char fpath[512];
     int tag, vno;
@@ -2691,6 +2779,9 @@ DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
     char stmp[16];
     FdHandle_t linkHandle;
     char dirl;
+    VolumeId volid = myIH->ih_vid;
+
+    memset(&linkHandle, 0, sizeof(linkHandle));
 
     snprintf(fpath, sizeof(fpath), "%s" OS_DIRSEP "%s", dpath, name);
 
@@ -2757,12 +2848,16 @@ DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
 #else
 static int
 DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
-           unsigned int volid)
+           IHandle_t *myIH)
 {
     char fpath[512];
     struct afs_stat_st status;
+    struct afs_stat_st checkstatus;
     int parm, tag;
     lb64_string_t check;
+    VolumeId volid = myIH->ih_vid;
+    IHandle_t tmpih;
+    namei_t nameiname;
 
     snprintf(fpath, sizeof(fpath), "%s" OS_DIRSEP "%s", dpath, name);
 
@@ -2777,6 +2872,36 @@ DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
     if (strcmp(name, check))
        return -1;
 
+    /* Check if the _full_ path is correct, to ensure we can actually open this
+     * file later. Otherwise, the salvager can choke. */
+    memset(&tmpih, 0, sizeof(tmpih));
+    tmpih.ih_dev = myIH->ih_dev;
+    tmpih.ih_vid = myIH->ih_vid;
+    tmpih.ih_ino = info->inodeNumber;
+    namei_HandleToName(&nameiname, &tmpih);
+    if ((afs_stat(nameiname.n_path, &checkstatus) < 0) ||
+        checkstatus.st_ino != status.st_ino ||
+        checkstatus.st_size != status.st_size) {
+       static int logged;
+       /* log something for this case, since this means the filename looks
+        * like a valid inode, but it's just in the wrong place. That's pretty
+        * strange. */
+       if (!logged) {
+           logged = 1;
+           Log("Note:\n");
+           Log("  Seemingly-misplaced files have been found, which I am\n");
+           Log("  ignoring for now. If you cannot salvage the relevant volume,\n");
+           Log("  you may try manually moving them to their correct location.\n");
+           Log("  If the relevant volume seems fine, and these files do not\n");
+           Log("  appear to contain important data, you can probably manually\n");
+           Log("  delete them, or leave them alone. Contact your local OpenAFS\n");
+           Log("  expert if you are unsure.\n");
+       }
+       Log("Ignoring misplaced file in volume group %u: %s (should be %s)\n",
+           (unsigned)myIH->ih_vid, fpath, nameiname.n_path);
+       return -1;
+    }
+
     if ((info->inodeNumber & NAMEI_INODESPECIAL) == NAMEI_INODESPECIAL) {
        parm = ((info->inodeNumber >> NAMEI_UNIQSHIFT) & NAMEI_UNIQMASK);
        tag = (int)((info->inodeNumber >> NAMEI_TAGSHIFT) & NAMEI_TAGMASK);
@@ -2806,15 +2931,15 @@ DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
 
 #ifdef FSSYNC_BUILD_CLIENT
 static afs_int32
-convertVolumeInfo(FD_t fdr, FD_t fdw, afs_uint32 vid)
+convertVolumeInfo(FD_t fdr, FD_t fdw, VolumeId vid)
 {
     struct VolumeDiskData vd;
     char *p;
 
     if (OS_READ(fdr, &vd, sizeof(struct VolumeDiskData)) !=
        sizeof(struct VolumeDiskData)) {
-       Log("1 convertVolumeInfo: read failed for %lu with code %d\n",
-           afs_printable_uint32_lu(vid),
+       Log("1 convertVolumeInfo: read failed for %" AFS_VOLID_FMT " with code %d\n",
+           afs_printable_VolumeId_lu(vid),
            errno);
        return -1;
     }
@@ -2876,7 +3001,7 @@ convertVolumeInfo(FD_t fdr, FD_t fdw, afs_uint32 vid)
  */
 
 int
-namei_ConvertROtoRWvolume(char *pname, afs_uint32 volumeId)
+namei_ConvertROtoRWvolume(char *pname, VolumeId volumeId)
 {
     int code = 0;
 #ifdef FSSYNC_BUILD_CLIENT
@@ -2965,7 +3090,7 @@ namei_ConvertROtoRWvolume(char *pname, afs_uint32 volumeId)
        if (*dp->d_name == '.')
            continue;
 #endif
-       if (DecodeInode(dir_name, dp->d_name, &info, ih->ih_vid) < 0) {
+       if (DecodeInode(dir_name, dp->d_name, &info, ih) < 0) {
            Log("1 namei_ConvertROtoRWvolume: DecodeInode failed for %s" OS_DIRSEP "%s\n",
                dir_name, dp->d_name);
            closedir(dirp);
@@ -3003,7 +3128,7 @@ namei_ConvertROtoRWvolume(char *pname, afs_uint32 volumeId)
            largeSeen = 1;
        } else {
            closedir(dirp);
-           Log("1 namei_ConvertROtoRWvolume: unknown type %d of special file found : %s" OS_DIRSEP "%s\n", info.u.param[2], dir_name, dp->d_name);
+           Log("1 namei_ConvertROtoRWvolume: unknown type %u of special file found : %s" OS_DIRSEP "%s\n", info.u.param[2], dir_name, dp->d_name);
            code = -1;
            goto done;
        }
@@ -3025,8 +3150,13 @@ namei_ConvertROtoRWvolume(char *pname, afs_uint32 volumeId)
     t_ih.ih_dev = ih->ih_dev;
     t_ih.ih_vid = ih->ih_vid;
 
-    snprintf(oldpath, sizeof oldpath, "%s" OS_DIRSEP "%s", dir_name,
-            infoName);
+    code = snprintf(oldpath, sizeof oldpath, "%s" OS_DIRSEP "%s", dir_name,
+                   infoName);
+    if (code < 0 || code >= sizeof(oldpath)) {
+       /* error, or truncated */
+       code = -1;
+       goto done;
+    }
     fd = OS_OPEN(oldpath, O_RDWR, 0);
     if (fd == INVALID_FD) {
        Log("1 namei_ConvertROtoRWvolume: could not open RO info file: %s\n",
@@ -3056,8 +3186,13 @@ namei_ConvertROtoRWvolume(char *pname, afs_uint32 volumeId)
 
     t_ih.ih_ino = namei_MakeSpecIno(ih->ih_vid, VI_SMALLINDEX);
     namei_HandleToName(&n, &t_ih);
-    snprintf(newpath, sizeof newpath, "%s" OS_DIRSEP "%s", dir_name,
-            smallName);
+    code = snprintf(newpath, sizeof newpath, "%s" OS_DIRSEP "%s", dir_name,
+                   smallName);
+    if (code < 0 || code >= sizeof(newpath)) {
+       /* error, or truncated */
+       code = -1;
+       goto done;
+    }
     fd = OS_OPEN(newpath, O_RDWR, 0);
     if (fd == INVALID_FD) {
        Log("1 namei_ConvertROtoRWvolume: could not open SmallIndex file: %s\n", newpath);
@@ -3069,14 +3204,23 @@ namei_ConvertROtoRWvolume(char *pname, afs_uint32 volumeId)
 #ifdef AFS_NT40_ENV
     MoveFileEx(n.n_path, newpath, MOVEFILE_WRITE_THROUGH);
 #else
-    link(newpath, n.n_path);
+    if (link(newpath, n.n_path)) {
+       Log("1 namei_ConvertROtoRWvolume: could not move SmallIndex file: %s\n", n.n_path);
+       code = -1;
+       goto done;
+    }
     OS_UNLINK(newpath);
 #endif
 
     t_ih.ih_ino = namei_MakeSpecIno(ih->ih_vid, VI_LARGEINDEX);
     namei_HandleToName(&n, &t_ih);
-    snprintf(newpath, sizeof newpath, "%s" OS_DIRSEP "%s", dir_name,
-            largeName);
+    code = snprintf(newpath, sizeof newpath, "%s" OS_DIRSEP "%s", dir_name,
+                   largeName);
+    if (code < 0 || code >= sizeof(newpath)) {
+       /* error, or truncated */
+       code = -1;
+       goto done;
+    }
     fd = OS_OPEN(newpath, O_RDWR, 0);
     if (fd == INVALID_FD) {
        Log("1 namei_ConvertROtoRWvolume: could not open LargeIndex file: %s\n", newpath);
@@ -3088,7 +3232,11 @@ namei_ConvertROtoRWvolume(char *pname, afs_uint32 volumeId)
 #ifdef AFS_NT40_ENV
     MoveFileEx(n.n_path, newpath, MOVEFILE_WRITE_THROUGH);
 #else
-    link(newpath, n.n_path);
+    if (link(newpath, n.n_path)) {
+       Log("1 namei_ConvertROtoRWvolume: could not move LargeIndex file: %s\n", n.n_path);
+       code = -1;
+       goto done;
+    }
     OS_UNLINK(newpath);
 #endif
 
@@ -3115,6 +3263,7 @@ namei_ConvertROtoRWvolume(char *pname, afs_uint32 volumeId)
     FSYNC_VolOp(volumeId, pname, FSYNC_VOL_DONE, 0, NULL);
     FSYNC_VolOp(h.id, pname, FSYNC_VOL_ON, 0, NULL);
 
+    code = 0;
  done:
 # ifdef AFS_DEMAND_ATTACH_FS
     if (locktype) {
@@ -3226,4 +3375,37 @@ FreeZLCList(void)
 }
 #endif
 
+/**
+ * Remove empty directories associated with the volume received
+ * as an argument.
+ *
+ * @param[in] pname    vice partition path
+ * @param[in] vid      volume id
+ *
+ * @return 0 on success
+ */
+int
+namei_RemoveDirectories(char *pname, afs_int32 vid)
+{
+    IHandle_t dirIH;
+    namei_t name;
+
+    memset(&dirIH, 0, sizeof(dirIH));
+
+    dirIH.ih_vid = vid;
+
+#ifdef AFS_NT40_ENV
+    dirIH.ih_dev = nt_DriveToDev(pname);
+#else
+    dirIH.ih_dev = volutil_GetPartitionID(pname);
+#endif
+    if (dirIH.ih_dev == -1) {
+       return -1;
+    }
+
+    namei_HandleToVolDir(&name, &dirIH);
+
+    return namei_RemoveDataDirectories(&name);
+}
+
 #endif /* AFS_NAMEI_ENV */