merge ntops and namei
[openafs.git] / src / vol / ntops.c
index 835bc51..5ee3f2f 100644 (file)
 
 #define BASEFILEATTRIBUTE FILE_ATTRIBUTE_NORMAL
 
-int Testing = 0;
-
-static void AddToZLCDeleteList(char dir, char *name);
-
 /* nt_unlink - unlink a case sensitive name.
  *
  * nt_unlink supports the nt_dec call.
@@ -224,37 +220,6 @@ nt_pread(FD_t fd, void * buf, size_t count, afs_foff_t offset)
 }
 
 int
-nt_iread(IHandle_t * h, int offset, char *buf, int size)
-{
-    int nBytes;
-    FdHandle_t *fdP;
-
-    fdP = IH_OPEN(h);
-    if (fdP == NULL)
-       return -1;
-
-    nBytes = FDH_PREAD(fdP, buf, size, offset);
-    FDH_CLOSE(fdP);
-    return nBytes;
-}
-
-int
-nt_iwrite(IHandle_t * h, int offset, char *buf, int size)
-{
-    int nBytes;
-    FdHandle_t *fdP;
-
-    fdP = IH_OPEN(h);
-    if (fdP == NULL)
-       return -1;
-
-    nBytes = FDH_PWRITE(fdP, buf, size, offset);
-    FDH_CLOSE(fdP);
-    return nBytes;
-}
-
-
-int
 nt_size(FD_t fd)
 {
     BY_HANDLE_FILE_INFORMATION finfo;
@@ -347,32 +312,6 @@ nt_seek(FD_t fd, int off, int where)
     return code;
 }
 
-
-/* Inode number format:
- * low 32 bits - if a regular file or directory, the vnode. Else the type.
- * 32-36 - unquifier tag and index into counts array for this vnode. Only
- *         two of the available bits are currently used. The rest are
- *         present in case we ever increase the number of types of volumes
- *         in the volume grou.
- * bit 37 : 1  == special, 0 == regular
- */
-#define NT_VNODEMASK    0x00ffffffff
-/* While the TAGMASK is 7, note that we are leaving 1 more bit available. */
-#define NT_TAGMASK      0x7
-#define NT_TAGSHIFT     32
-#define NT_INODESPECIAL 0x2000000000
-
-#define NT_MAXVOLS 5           /* Maximum supported number of volumes per volume
-                                * group, not counting temporary (move) volumes.
-                                * This is the number of separate files, all having
-                                * the same vnode number, which can occur in a volume
-                                * group at once.
-                                */
-
-
-int nt_SetLinkCount(FdHandle_t * h, Inode ino, int count, int locked);
-
-
 /* nt_DevToDrive
  * converts a device number (2-25) into a drive letter name.
  *
@@ -384,1017 +323,39 @@ int nt_SetLinkCount(FdHandle_t * h, Inode ino, int count, int locked);
  * Returns pointer to end of drive if successful, else NULL.
  *
  */
-char *
+void
 nt_DevToDrive(char *drive, int dev)
 {
     if (dev < 2 || dev > 25) {
        errno = EINVAL;
-       return NULL;            /* Invalid drive */
+       return;         /* Invalid drive */
     }
     drive[0] = (char)('A' + dev);
     drive[1] = ':';
     drive[2] = '\0';
 
-    return drive + 2;
-
-}
-
-/* Returns pointer to end of name if successful, else NULL. */
-char *
-nt_HandleToVolDir(char *name, IHandle_t * h)
-{
-    b32_string_t str1;
-
-    if (!(name = nt_DevToDrive(name, h->ih_dev)))
-       return NULL;
-
-    (void)memcpy(name, "\\Vol_", 5);
-    name += 5;
-    (void)strcpy(name, int_to_base32(str1, h->ih_vid));
-    name += strlen(name);
-    memcpy(name, ".data", 5);
-    name += 5;
-    *name = '\0';
-
-    return name;
-}
-
-/* nt_HandleToName
- *
- * Constructs a file name for the fully qualified handle.
- */
-int
-nt_HandleToName(char *name, IHandle_t * h)
-{
-    b32_string_t str1;
-    int tag = (int)((h->ih_ino >> NT_TAGSHIFT) & NT_TAGMASK);
-    int vno = (int)(h->ih_ino & NT_VNODEMASK);
-
-    if (!(name = nt_HandleToVolDir(name, h)))
-       return -1;
-
-    str1[0] = '\\';
-    if (h->ih_ino & NT_INODESPECIAL)
-       str1[1] = 'R';
-    else {
-       if (vno & 0x1)
-           str1[1] = 'Q';
-       else
-           str1[1] = ((vno & 0x1f) >> 1) + 'A';
-    }
-
-    memcpy(name, str1, 2);
-    name += 2;
-    (void)memcpy(name, "\\V_", 3);
-    name += 3;
-    (void)strcpy(name, int_to_base32(str1, vno));
-    name += strlen(name);
-    *(name++) = '.';
-    (void)strcpy(name, int_to_base32(str1, tag));
-    name += strlen(name);
-    *name = '\0';
-
-    return 0;
-}
-
-/* nt_CreateDataDirectories
- *
- * The data for each volume is in a separate directory. The name of the
- * volume is of the form: Vol_NNNNNN.data, where NNNNNN is a base 32
- * representation of the RW volume ID (even where the RO is the only volume
- * on the partition). Below that are separate subdirectories for the
- * AFS directories and special files. There are also 16 directories for files,
- * hashed on the low 5 bits (recall bit0 is always 0) of the vnode number.
- * These directories are named:
- * A - P - 16 file directories.
- * Q ----- data directory
- * R ----- special files directory
- */
-static int
-nt_CreateDataDirectories(IHandle_t * h, int *created)
-{
-    char name[128];
-    char *s;
-    int i;
-
-    if (!(s = nt_HandleToVolDir(name, h)))
-       return -1;
-
-    if (mkdir(name) < 0) {
-       if (errno != EEXIST)
-           return -1;
-    } else
-       *created = 1;
+    return;
 
-    *s++ = '\\';
-    *(s + 1) = '\0';
-    for (i = 'A'; i <= 'R'; i++) {
-       *s = (char)i;
-       if (mkdir(name) < 0 && errno != EEXIST)
-           return -1;
-    }
-    return 0;
 }
 
-/* nt_RemoveDataDirectories
+/* nt_DriveToDev
+ * converts a drive letter to a device number (2-25)
  *
- * Returns -1 on error. Typically, callers ignore this error bcause we
- * can continue running if the removes fail. The salvage process will
- * finish tidying up for us.
- */
-static int
-nt_RemoveDataDirectories(IHandle_t * h)
-{
-    char name[128];
-    char *s;
-    int i;
-
-    if (!(s = nt_HandleToVolDir(name, h)))
-       return -1;
-
-    *s++ = '\\';
-    *(s + 1) = '\0';
-    for (i = 'A'; i <= 'R'; i++) {
-       *s = (char)i;
-       if (rmdir(name) < 0 && errno != ENOENT)
-           return -1;
-    }
-
-    /* Delete the Vol_NNNNNN.data directory. */
-    s--;
-    *s = '\0';
-    if (rmdir(name) < 0 && errno != ENOENT) {
-       return -1;
-    }
-
-    return 0;
-}
-
-
-/* Create the file in the name space.
- *
- * Parameters stored as follows:
- * Regular files:
- * p1 - volid - implied in containing directory.
- * p2 - vnode - name is <vnode>.<tag> where tag is a file name unqiquifier.
- * p3 - uniq -- creation time - dwHighDateTime
- * p4 - dv ---- creation time - dwLowDateTime
- * Special files:
- * p1 - volid - creation time - dwHighDateTime
- * p2 - vnode - -1 means special, file goes in "S" subdirectory.
- * p3 - type -- name is <type>.<tag> where tag is a file name unqiquifier.
- * p4 - parid - parent volume id - implied in containing directory.
+ * Arguments:
+ * drive - assumes drive is a pointer to a string at least 3 bytes long.
  *
- * Return value is the inode number or (Inode)-1 if error.
- * We "know" there is only one link table, so return EEXIST if there already
- * is a link table. It's up to the calling code to test errno and increment
- * the link count.
- */
-
-/* nt_MakeSpecIno
+ * Return Value:
+ * dev   - drive number 2-25 if successful (A-C already in use), else -1
  *
- * This function is called by VCreateVolume to hide the implementation
- * details of the inode numbers.
- */
-Inode
-nt_MakeSpecIno(int type)
-{
-    return ((Inode) type | (Inode) NT_INODESPECIAL);
-}
-
-Inode
-nt_icreate(IHandle_t * h, char *part, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4)
-{
-    char filename[128];
-    b32_string_t str1;
-    char *p;
-    int i;
-    FD_t fd;
-    int created_dir = 0;
-    int code = 0;
-    FILETIME ftime;
-    IHandle_t tmp;
-    FdHandle_t *fdP;
-    FdHandle_t tfd;
-    int save_errno;
-
-    memset((void *)&tmp, 0, sizeof(IHandle_t));
-
-
-    tmp.ih_dev = tolower(*part) - 'a';
-
-    if (p2 == -1) {
-       tmp.ih_vid = p4;        /* Use parent volume id, where this file will be. */
-
-       if (nt_CreateDataDirectories(&tmp, &created_dir) < 0)
-           goto bad;
-
-       tmp.ih_ino = nt_MakeSpecIno(p3);
-       ftime.dwHighDateTime = p1;
-       ftime.dwLowDateTime = p2;
-    } else {
-       /* Regular file or directory.
-        * Encoding: p1 -> dir,  p2 -> name, p3,p4 -> Create time
-        */
-       tmp.ih_ino = (Inode) p2;
-       tmp.ih_vid = p1;
-
-       ftime.dwHighDateTime = p3;
-       ftime.dwLowDateTime = p4;
-    }
-
-    /* Now create file. */
-    if ((code = nt_HandleToName(filename, &tmp)) < 0)
-       goto bad;
-
-    p = filename + strlen(filename);
-    p--;
-    for (i = 0; i < NT_MAXVOLS; i++) {
-       *p = *int_to_base32(str1, i);
-       fd = nt_open(filename, O_CREAT | O_RDWR | O_TRUNC | O_EXCL, 0666);
-       if (fd != INVALID_FD)
-           break;
-       if (p2 == -1 && p3 == VI_LINKTABLE)
-           break;
-    }
-    if (fd == INVALID_FD) {
-       code = -1;
-       goto bad;
-    }
-
-    tmp.ih_ino &= ~((Inode) NT_TAGMASK << NT_TAGSHIFT);
-    tmp.ih_ino |= ((Inode) i << NT_TAGSHIFT);
-
-    if (!code) {
-       if (!SetFileTime((HANDLE) fd, &ftime, NULL, NULL)) {
-           errno = EBADF;
-           code = -1;
-       }
-    }
-
-    if (!code) {
-       if (p2 != -1) {
-           if (fd == INVALID_FD) {
-               errno = ENOENT;
-               code = nt_unlink(filename);
-               if (code == -1) {
-               }
-               code = -1;
-               goto bad;
-           }
-           fdP = IH_OPEN(h);
-           if (fdP == NULL) {
-               code = -1;
-               goto bad;
-           }
-           code = nt_SetLinkCount(fdP, tmp.ih_ino, 1, 0);
-           FDH_CLOSE(fdP);
-       } else if (p2 == -1 && p3 == VI_LINKTABLE) {
-           if (fd == INVALID_FD)
-               goto bad;
-           /* hack at tmp to setup for set link count call. */
-           tfd.fd_fd = fd;
-           code = nt_SetLinkCount(&tfd, (Inode) 0, 1, 0);
-       }
-    }
-
-  bad:
-    if (fd != INVALID_FD)
-       nt_close(fd);
-
-    if (code && created_dir) {
-       save_errno = errno;
-       nt_RemoveDataDirectories(&tmp);
-       errno = save_errno;
-    }
-    return code ? (Inode) - 1 : tmp.ih_ino;
-}
-
-
-FD_t
-nt_iopen(IHandle_t * h)
-{
-    FD_t fd;
-    char name[128];
-
-    /* Convert handle to file name. */
-    if (nt_HandleToName(name, h) < 0)
-       return INVALID_FD;
-
-    fd = nt_open(name, O_RDWR, 0666);
-    return fd;
-}
-
-/* Need to detect vol special file and just unlink. In those cases, the
- * handle passed in _is_ for the inode. We only check p1 for the special
- * files.
  */
 int
-nt_dec(IHandle_t * h, Inode ino, int p1)
+nt_DriveToDev(char *drive)
 {
-    int count = 0;
-    char name[128];
-    int code = 0;
-    FdHandle_t *fdP;
-
-    if (ino & NT_INODESPECIAL) {
-       IHandle_t *tmp;
-       int was_closed = 0;
-       WIN32_FIND_DATA info;
-       HANDLE dirH;
-
-       /* Verify this is the right file. */
-       IH_INIT(tmp, h->ih_dev, h->ih_vid, ino);
-
-       if (nt_HandleToName(name, tmp) < 0) {
-           IH_RELEASE(tmp);
-           errno = EINVAL;
-           return -1;
-       }
-
-       dirH =
-           FindFirstFileEx(name, FindExInfoStandard, &info,
-                           FindExSearchNameMatch, NULL,
-                           FIND_FIRST_EX_CASE_SENSITIVE);
-       if (!dirH) {
-           IH_RELEASE(tmp);
-           errno = ENOENT;
-           return -1;          /* Can't get info, leave alone */
-       }
+    int dev = -1;
 
-       FindClose(dirH);
-       if (info.ftCreationTime.dwHighDateTime != (unsigned int)p1) {
-           IH_RELEASE(tmp);
-           return -1;
-       }
-
-       /* If it's the link table itself, decrement the link count. */
-       if ((ino & NT_VNODEMASK) == VI_LINKTABLE) {
-           fdP = IH_OPEN(tmp);
-           if (fdP == NULL) {
-               IH_RELEASE(tmp);
-               return -1;
-           }
-
-           if ((count = nt_GetLinkCount(fdP, (Inode) 0, 1)) < 0) {
-               FDH_REALLYCLOSE(fdP);
-               IH_RELEASE(tmp);
-               return -1;
-           }
-
-           count--;
-           if (nt_SetLinkCount(fdP, (Inode) 0, count < 0 ? 0 : count, 1) < 0) {
-               FDH_REALLYCLOSE(fdP);
-               IH_RELEASE(tmp);
-               return -1;
-           }
-
-           FDH_REALLYCLOSE(fdP);
-           if (count > 0) {
-               IH_RELEASE(tmp);
-               return 0;
-           }
-       }
-
-       if ((code = nt_unlink(name)) == 0) {
-           if ((ino & NT_VNODEMASK) == VI_LINKTABLE) {
-               /* Try to remove directory. If it fails, that's ok.
-                * Salvage will clean up.
-                */
-               (void)nt_RemoveDataDirectories(tmp);
-           }
-       }
-
-       IH_RELEASE(tmp);
-    } else {
-       /* Get a file descriptor handle for this Inode */
-       fdP = IH_OPEN(h);
-       if (fdP == NULL) {
-           return -1;
-       }
-
-       if ((count = nt_GetLinkCount(fdP, ino, 1)) < 0) {
-           FDH_REALLYCLOSE(fdP);
-           return -1;
-       }
-
-       count--;
-       if (count >= 0) {
-           if (nt_SetLinkCount(fdP, ino, count, 1) < 0) {
-               FDH_REALLYCLOSE(fdP);
-               return -1;
-           }
-       }
-       if (count == 0) {
-           IHandle_t th = *h;
-           th.ih_ino = ino;
-           nt_HandleToName(name, &th);
-           code = nt_unlink(name);
-       }
-       FDH_CLOSE(fdP);
-    }
-
-    return code;
-}
-
-int
-nt_inc(IHandle_t * h, Inode ino, int p1)
-{
-    int count;
-    int code = 0;
-    FdHandle_t *fdP;
-
-    if (ino & NT_INODESPECIAL) {
-       if ((ino & NT_VNODEMASK) != VI_LINKTABLE)
-           return 0;
-       ino = (Inode) 0;
-    }
-
-    /* Get a file descriptor handle for this Inode */
-    fdP = IH_OPEN(h);
-    if (fdP == NULL) {
+    if (drive)
+       dev = toupper(*drive) - 'A';
+    if ((dev < 2) || (dev > 25))
        return -1;
-    }
-
-    if ((count = nt_GetLinkCount(fdP, ino, 1)) < 0)
-       code = -1;
-    else {
-       count++;
-       if (count > 7) {
-           errno = EINVAL;
-           code = -1;
-           count = 7;
-       }
-       if (nt_SetLinkCount(fdP, ino, count, 1) < 0)
-           code = -1;
-    }
-    if (code) {
-       FDH_REALLYCLOSE(fdP);
-    } else {
-       FDH_CLOSE(fdP);
-    }
-    return code;
 }
-
-
-
-/************************************************************************
- *  Link Table Organization
- ************************************************************************
- *
- * The link table volume special file is used to hold the link counts that
- * are held in the inodes in inode based AFS vice filesystems. Since NTFS
- * doesn't provide us that access, the link counts are being kept in a separate
- * volume special file. The file begins with the usual version stamp
- * information and is then followed by one row per vnode number. vnode 0
- * is used to hold the link count of the link table itself. That is because
- * the same link table is shared among all the volumes of the volume group
- * and is deleted only when the last volume of a volume group is deleted.
- *
- * Within each row, the columns are 3 bits wide. They can each hold a 0 based
- * link count from 0 through 7. Each colume represents a unique instance of
- * that vnode. Say we have a file shared between the RW and a RO and a
- * different version of the file (or a different uniquifer) for the BU volume.
- * Then one column would be holding the link count of 2 for the RW and RO
- * and a different column would hold the link count of 1 for the BU volume.
- * The column used is determined for NT by the uiquifier tag applied to
- * generate a unique file name in the NTFS namespace. The file name is
- * of the form "V_<vno>.<tag>" . And the <tag> is also the column number
- * in the link table.
- */
-#define LINKTABLE_WIDTH 2
-#define LINKTABLE_SHIFT 1      /* log 2 = 1 */
-
-static void
-nt_GetLCOffsetAndIndexFromIno(Inode ino, int *offset, int *index)
-{
-    int toff = (int)(ino & NT_VNODEMASK);
-    int tindex = (int)((ino >> NT_TAGSHIFT) & NT_TAGMASK);
-
-    *offset = (toff << LINKTABLE_SHIFT) + 8;   /* *2 + sizeof stamp */
-    *index = (tindex << 1) + tindex;
-}
-
-
-/* nt_GetLinkCount
- * If lockit is set, lock the file and leave it locked upon a successful
- * return.
- */
-static int
-nt_GetLinkCountInternal(FdHandle_t * h, Inode ino, int lockit, int fixup)
-{
-    unsigned short row = 0;
-    DWORD bytesRead, bytesWritten;
-    int offset, index;
-
-    /* there's no linktable yet. the salvager will create one later */
-    if (h->fd_fd == INVALID_HANDLE_VALUE && fixup)
-       return 1;
-
-    nt_GetLCOffsetAndIndexFromIno(ino, &offset, &index);
-
-    if (lockit) {
-       if (!LockFile(h->fd_fd, offset, 0, 2, 0))
-           return -1;
-    }
-
-    if (!SetFilePointer(h->fd_fd, (LONG) offset, NULL, FILE_BEGIN))
-       goto bad_getLinkByte;
-
-    if (!ReadFile(h->fd_fd, (void *)&row, 2, &bytesRead, NULL))
-       goto bad_getLinkByte;
-
-    if (bytesRead == 0 && fixup) {
-       LARGE_INTEGER size;
-
-       if (!GetFileSizeEx(h->fd_fd, &size) || size.QuadPart >= offset+sizeof(row))
-           goto bad_getLinkByte;
-       FDH_TRUNC(h, offset+sizeof(row));
-       row = 1 << index;
-      rewrite:
-       WriteFile(h->fd_fd, (char *)&row, sizeof(row), &bytesWritten, NULL);
-    }
-
-    if (fixup && !((row >> index) & NT_TAGMASK)) {
-        row |= 1<<index;
-        goto rewrite;
-    }
-
-    return (int)((row >> index) & NT_TAGMASK);
-
-  bad_getLinkByte:
-    if (lockit)
-       UnlockFile(h->fd_fd, offset, 0, 2, 0);
-    return -1;
-}
-
-int
-nt_GetLinkCount(FdHandle_t * h, Inode ino, int lockit)
-{
-    return nt_GetLinkCountInternal(h, ino, lockit, 0);
-}
-
-void
-nt_SetNonZLC(FdHandle_t * h, Inode ino)
-{
-    (void)nt_GetLinkCountInternal(h, ino, 0, 1);
-}
-
-
-/* nt_SetLinkCount
- * If locked is set, assume file is locked. Otherwise, lock file before
- * proceeding to modify it.
- */
-int
-nt_SetLinkCount(FdHandle_t * h, Inode ino, int count, int locked)
-{
-    int offset, index;
-    unsigned short row;
-    DWORD bytesRead, bytesWritten;
-    int code = -1;
-
-    nt_GetLCOffsetAndIndexFromIno(ino, &offset, &index);
-
-
-    if (!locked) {
-       if (!LockFile(h->fd_fd, offset, 0, 2, 0)) {
-           errno = nterr_nt2unix(GetLastError(), EBADF);
-           return -1;
-       }
-    }
-    if (!SetFilePointer(h->fd_fd, (LONG) offset, NULL, FILE_BEGIN)) {
-       errno = nterr_nt2unix(GetLastError(), EBADF);
-       goto bad_SetLinkCount;
-    }
-
-
-    if (!ReadFile(h->fd_fd, (void *)&row, 2, &bytesRead, NULL)) {
-       errno = nterr_nt2unix(GetLastError(), EBADF);
-       goto bad_SetLinkCount;
-    }
-    if (bytesRead == 0)
-       row = 0;
-
-    bytesRead = 7 << index;
-    count <<= index;
-    row &= (unsigned short)~bytesRead;
-    row |= (unsigned short)count;
-
-    if (!SetFilePointer(h->fd_fd, (LONG) offset, NULL, FILE_BEGIN)) {
-       errno = nterr_nt2unix(GetLastError(), EBADF);
-       goto bad_SetLinkCount;
-    }
-
-    if (!WriteFile(h->fd_fd, (void *)&row, 2, &bytesWritten, NULL)) {
-       errno = nterr_nt2unix(GetLastError(), EBADF);
-       goto bad_SetLinkCount;
-    }
-
-    code = 0;
-
-
-  bad_SetLinkCount:
-    UnlockFile(h->fd_fd, offset, 0, 2, 0);
-
-    return code;
-}
-
-
-/* ListViceInodes - write inode data to a results file. */
-static int DecodeInodeName(char *name, int *p1, int *p2);
-static int DecodeVolumeName(char *name, afs_uint32 *vid);
-static int nt_ListAFSSubDirs(IHandle_t * dirIH,
-                            int (*write_fun) (FILE *, struct ViceInodeInfo *,
-                                              char *, char *), FILE * fp,
-                            int (*judgeFun) (struct ViceInodeInfo *,
-                                             afs_uint32 vid, void *rock),
-                            afs_uint32 singleVolumeNumber, void *rock);
-
-
-/* WriteInodeInfo
- *
- * Write the inode data to the results file.
- *
- * Returns -2 on error, 0 on success.
- *
- * This is written as a callback simply so that other listing routines
- * can use the same inode reading code.
- */
-static int
-WriteInodeInfo(FILE * fp, struct ViceInodeInfo *info, char *dir, char *name)
-{
-    int n;
-    n = fwrite(info, sizeof(*info), 1, fp);
-    return (n == 1) ? 0 : -2;
-}
-
-
-/* ListViceInodes
- * Fill the results file with the requested inode information.
- *
- * Return values:
- *  0 - success
- * -1 - complete failure, salvage should terminate.
- * -2 - not enough space on partition, salvager has error message for this.
- *
- * This code optimizes single volume salvages by just looking at that one
- * volume's directory.
- *
- * If the inodeFile is NULL, then don't call the write routine.
- */
-int
-ListViceInodes(char *devname, char *mountedOn, FILE *inodeFile,
-              int (*judgeInode) (struct ViceInodeInfo * info, afs_uint32 vid, void *rock),
-              afs_uint32 singleVolumeNumber, int *forcep, int forceR, char *wpath,
-              void *rock)
-{
-    int ninodes;
-    struct stat status;
-
-    ninodes =
-       nt_ListAFSFiles(wpath, WriteInodeInfo, inodeFile, judgeInode,
-                       singleVolumeNumber, rock);
-
-    if (!inodeFile)
-       return ninodes;
-
-    if (ninodes < 0) {
-       return ninodes;
-    }
-
-    if (fflush(inodeFile) == EOF) {
-       Log("Unable to successfully flush inode file for %s\n", mountedOn);
-       return -2;
-    }
-    if (fsync(fileno(inodeFile)) == -1) {
-       Log("Unable to successfully fsync inode file for %s\n", mountedOn);
-       return -2;
-    }
-
-    /*
-     * Paranoia:  check that the file is really the right size
-     */
-    if (fstat(fileno(inodeFile), &status) == -1) {
-       Log("Unable to successfully stat inode file for %s\n", mountedOn);
-       return -2;
-    }
-    if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
-       Log("Wrong size (%d instead of %d) in inode file for %s\n",
-           status.st_size, ninodes * sizeof(struct ViceInodeInfo),
-           mountedOn);
-       return -2;
-    }
-    return 0;
-}
-
-
-/* nt_ListAFSFiles
- *
- * Collect all the matching AFS files on the drive.
- * If singleVolumeNumber is non-zero, just return files for that volume.
- *
- * Returns <0 on error, else number of files found to match.
- */
-int
-nt_ListAFSFiles(char *dev,
-               int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
-                                char *), FILE * fp,
-               int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *),
-               afs_uint32 singleVolumeNumber, void *rock)
-{
-    IHandle_t h;
-    char name[MAX_PATH];
-    int ninodes = 0;
-    DIR *dirp;
-    struct dirent *dp;
-    static void FreeZLCList(void);
-
-    memset((void *)&h, 0, sizeof(IHandle_t));
-    h.ih_dev = toupper(*dev) - 'A';
-
-    if (singleVolumeNumber) {
-       h.ih_vid = singleVolumeNumber;
-       if (!nt_HandleToVolDir(name, &h))
-           return -1;
-       ninodes =
-           nt_ListAFSSubDirs(&h, writeFun, fp, judgeFun, singleVolumeNumber, rock);
-       if (ninodes < 0)
-           return ninodes;
-    } else {
-       /* Find all Vol_*.data directories and descend through them. */
-       if (!nt_DevToDrive(name, h.ih_dev))
-           return -1;
-       ninodes = 0;
-       dirp = opendir(name);
-       if (!dirp)
-           return -1;
-       while (dp = readdir(dirp)) {
-           if (!DecodeVolumeName(dp->d_name, &h.ih_vid)) {
-               ninodes += nt_ListAFSSubDirs(&h, writeFun, fp, judgeFun, 0, rock);
-           }
-       }
-    }
-    FreeZLCList();
-    return ninodes;
-}
-
-
-
-/* nt_ListAFSSubDirs
- *
- * List the S, F, and D subdirectories of this volume's directory.
- *
- * Return values:
- * < 0 - an error
- * > = 0 - number of AFS files found.
- */
-static int
-nt_ListAFSSubDirs(IHandle_t * dirIH,
-                 int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
-                                  char *), FILE * fp,
-                 int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *),
-                 afs_uint32 singleVolumeNumber, void *rock)
-{
-    int i;
-    IHandle_t myIH = *dirIH;
-    HANDLE dirH;
-    WIN32_FIND_DATA data;
-    char path[1024];
-    char basePath[1024];
-    char *s;
-    char findPath[1024];
-    struct ViceInodeInfo info;
-    int tag, vno;
-    FdHandle_t linkHandle;
-    int ninodes = 0;
-    static void DeleteZLCFiles(char *path);
-
-    s = nt_HandleToVolDir(path, &myIH);
-    strcpy(basePath, path);
-    if (!s)
-       return -1;
-    *s = '\\';
-    s++;
-    *(s + 1) = '\0';
-
-    /* Do the directory containing the special files first to pick up link
-     * counts.
-     */
-    for (i = 'R'; i >= 'A'; i--) {
-       *s = (char)i;
-       (void)strcpy(findPath, path);
-       (void)strcat(findPath, "\\*");
-       dirH =
-           FindFirstFileEx(findPath, FindExInfoStandard, &data,
-                           FindExSearchNameMatch, NULL,
-                           FIND_FIRST_EX_CASE_SENSITIVE);
-       if (dirH == INVALID_HANDLE_VALUE)
-           continue;
-       while (1) {
-           /* Store the vice info. */
-           memset((void *)&info, 0, sizeof(info));
-           if (*data.cFileName == '.')
-               goto next_file;
-           if (DecodeInodeName(data.cFileName, &vno, &tag) < 0) {
-               Log("Error parsing %s\\%s\n", path, data.cFileName);
-           } else {
-               info.inodeNumber = (Inode) tag << NT_TAGSHIFT;
-               info.inodeNumber |= (Inode) vno;
-               info.byteCount = data.nFileSizeLow;
-
-               if (i == 'R') { /* Special inode. */
-                   info.inodeNumber |= NT_INODESPECIAL;
-                   info.u.param[0] = data.ftCreationTime.dwHighDateTime;
-                   info.u.param[1] = data.ftCreationTime.dwLowDateTime;
-                   info.u.param[2] = vno;
-                   info.u.param[3] = dirIH->ih_vid;
-                   if (info.u.param[2] != VI_LINKTABLE) {
-                       info.linkCount = 1;
-                   } else {
-                       /* Open this handle */
-                       char lpath[1024];
-                       (void)sprintf(lpath, "%s\\%s", path, data.cFileName);
-                       linkHandle.fd_fd = nt_open(lpath, O_RDONLY, 0666);
-                       info.linkCount =
-                           nt_GetLinkCount(&linkHandle, (Inode) 0, 0);
-                   }
-               } else {        /* regular file. */
-                   info.linkCount =
-                       nt_GetLinkCount(&linkHandle, info.inodeNumber, 0);
-                   if (info.linkCount == 0) {
-#ifdef notdef
-                       Log("Found 0 link count file %s\\%s, deleting it.\n",
-                           path, data.cFileName);
-                       AddToZLCDeleteList((char)i, data.cFileName);
-#else
-                       Log("Found 0 link count file %s\\%s.\n", path,
-                           data.cFileName);
 #endif
-                       goto next_file;
-                   }
-                   info.u.param[0] = dirIH->ih_vid;
-                   info.u.param[1] = vno;
-                   info.u.param[2] = data.ftCreationTime.dwHighDateTime;
-                   info.u.param[3] = data.ftCreationTime.dwLowDateTime;
-               }
-               if (judgeFun && !(*judgeFun) (&info, singleVolumeNumber, rock))
-                   goto next_file;
-               if ((*writeFun) (fp, &info, path, data.cFileName) < 0) {
-                   nt_close(linkHandle.fd_fd);
-                   FindClose(dirH);
-                   return -1;
-               }
-               ninodes++;
-           }
-         next_file:
-           if (!FindNextFile(dirH, &data)) {
-               break;
-           }
-       }
-       FindClose(dirH);
-    }
-    nt_close(linkHandle.fd_fd);
-    DeleteZLCFiles(basePath);
-    if (!ninodes) {
-       /* Then why does this directory exist? Blow it away. */
-       nt_RemoveDataDirectories(dirIH);
-    }
-
-    return ninodes;
-}
-
-/* The name begins with "Vol_" and ends with .data.  See nt_HandleToVolDir() */
-static int
-DecodeVolumeName(char *name, afs_uint32 *vid)
-{
-    char stmp[32];
-    int len;
-
-    len = strlen(name);
-    if (len <= 9)
-       return -1;
-    if (strncmp(name, "Vol_", 4))
-       return -1;
-    if (strcmp(name + len - 5, ".data"))
-       return -1;
-    strcpy(stmp, name);
-    stmp[len - 5] = '\0';
-    *vid = base32_to_int(stmp + 4);
-    return 0;
-}
-
-/* Recall that the name beings with a "V_" */
-static int
-DecodeInodeName(char *name, int *p1, int *p2)
-{
-    char *s, *t;
-    char stmp[16];
-
-    (void)strcpy(stmp, name);
-    s = strrchr(stmp, '_');
-    if (!s)
-       return -1;
-    s++;
-    t = strrchr(s, '.');
-    if (!t)
-       return -1;
-
-    *t = '\0';
-    *p1 = base32_to_int(s);
-    *p2 = base32_to_int(t + 1);
-    return 0;
-}
-
-
-/* PrintInode
- *
- * returns a static string used to print either 32 or 64 bit inode numbers.
- */
-char *
-PrintInode(char *s, Inode ino)
-{
-    static afs_ino_str_t result;
-    if (!s)
-       s = result;
-
-    (void)sprintf((char *)s, "%I64u", ino);
-
-    return (char *)s;
-}
-
-
-/* Routines to facilitate removing zero link count files. */
-#define MAX_ZLC_NAMES 32
-#define MAX_ZLC_NAMELEN 16
-typedef struct zlcList_s {
-    struct zlcList_s *zlc_next;
-    int zlc_n;
-    char zlc_names[MAX_ZLC_NAMES][MAX_ZLC_NAMELEN];
-} zlcList_t;
-
-static zlcList_t *zlcAnchor = NULL;
-static zlcList_t *zlcCur = NULL;
-
-static void
-AddToZLCDeleteList(char dir, char *name)
-{
-    osi_Assert(strlen(name) <= MAX_ZLC_NAMELEN - 3);
-
-    if (!zlcCur || zlcCur->zlc_n >= MAX_ZLC_NAMES) {
-       if (zlcCur && zlcCur->zlc_next)
-           zlcCur = zlcCur->zlc_next;
-       else {
-           zlcList_t *tmp = (zlcList_t *) malloc(sizeof(zlcList_t));
-           if (!tmp)
-               return;
-           if (!zlcAnchor) {
-               zlcAnchor = tmp;
-           } else {
-               zlcCur->zlc_next = tmp;
-           }
-           zlcCur = tmp;
-           zlcCur->zlc_n = 0;
-           zlcCur->zlc_next = NULL;
-       }
-    }
-
-    (void)sprintf(zlcCur->zlc_names[zlcCur->zlc_n], "%c\\%s", dir, name);
-    zlcCur->zlc_n++;
-}
-
-static void
-DeleteZLCFiles(char *path)
-{
-    zlcList_t *z;
-    int i;
-    char fname[1024];
-
-    for (z = zlcAnchor; z; z = z->zlc_next) {
-       for (i = 0; i < z->zlc_n; i++) {
-           (void)sprintf(fname, "%s\\%s", path, z->zlc_names[i]);
-           if (nt_unlink(fname) < 0) {
-               Log("ZLC: Can't unlink %s, dos error = %d\n", fname,
-                   GetLastError());
-           }
-       }
-       z->zlc_n = 0;           /* Can reuse space. */
-    }
-    zlcCur = zlcAnchor;
-}
-
-static void
-FreeZLCList(void)
-{
-    zlcList_t *tnext;
-    zlcList_t *i;
-
-    i = zlcAnchor;
-    while (i) {
-       tnext = i->zlc_next;
-       free(i);
-       i = tnext;
-    }
-    zlcCur = zlcAnchor = NULL;
-}
-
-#endif /* AFS_NT40_ENV */