2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 /* I/O operations for the Windows NT platforms. */
12 #include <afsconfig.h>
13 #include <afs/param.h>
31 #include <afs/afsutil.h>
33 #include <afs/afsint.h>
37 #include "viceinode.h"
39 #include <afs/assert.h>
40 #include <afs/errmap_nt.h>
42 #define BASEFILEATTRIBUTE FILE_ATTRIBUTE_NORMAL
46 static void AddToZLCDeleteList(char dir, char *name);
48 /* nt_unlink - unlink a case sensitive name.
50 * nt_unlink supports the nt_dec call.
52 * This nt_unlink has the delete on last close semantics of the Unix unlink
53 * with a minor twist. Subsequent CreateFile calls on this file can succeed
54 * if they open for delete. It's also unclear what happens if a CreateFile
55 * call tries to create a new file with the same name. Fortunately, neither
56 * case should occur as part of nt_dec.
63 fh = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
64 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
66 BASEFILEATTRIBUTE | FILE_FLAG_DELETE_ON_CLOSE |
67 FILE_FLAG_POSIX_SEMANTICS, NULL);
68 if (fh != INVALID_HANDLE_VALUE)
71 errno = nterr_nt2unix(GetLastError(), ENOENT);
77 /* nt_open - open an NT handle for a file.
80 * the handle or -1 on error.
83 nt_open(char *name, int flags, int mode)
87 DWORD nt_share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
89 /* Really use the sequential one for data files, random for meta data. */
90 DWORD FandA = BASEFILEATTRIBUTE | FILE_FLAG_SEQUENTIAL_SCAN;
93 if ((flags & O_RDWR) || (flags & O_WRONLY))
94 nt_access |= GENERIC_WRITE;
95 if ((flags & O_RDWR) || (flags == O_RDONLY))
96 nt_access |= GENERIC_READ;
99 switch (flags & (O_CREAT | O_EXCL | O_TRUNC)) {
101 nt_create = OPEN_EXISTING;
104 nt_create = OPEN_ALWAYS;
106 case O_CREAT | O_TRUNC:
107 nt_create = CREATE_ALWAYS;
109 case O_CREAT | O_EXCL:
110 case O_CREAT | O_EXCL | O_TRUNC:
111 nt_create = CREATE_NEW;
114 nt_create = TRUNCATE_EXISTING;
116 case O_TRUNC | O_EXCL:
124 fh = CreateFile(name, nt_access, nt_share, NULL, nt_create, FandA, NULL);
126 if (fh == INVALID_HANDLE_VALUE) {
128 errno = nterr_nt2unix(GetLastError(), EBADF);
138 code = CloseHandle(fd);
140 errno = nterr_nt2unix(GetLastError(), EBADF);
147 nt_write(FD_t fd, char *buf, size_t size)
152 code = WriteFile((HANDLE) fd, (void *)buf, (DWORD) size, &nbytes, NULL);
155 errno = nterr_nt2unix(GetLastError(), EBADF);
162 nt_read(FD_t fd, char *buf, size_t size)
167 code = ReadFile((HANDLE) fd, (void *)buf, (DWORD) size, &nbytes, NULL);
170 errno = nterr_nt2unix(GetLastError(), EBADF);
177 nt_iread(IHandle_t * h, int offset, char *buf, int size)
186 if (FDH_SEEK(fdP, offset, SEEK_SET) < 0) {
187 FDH_REALLYCLOSE(fdP);
191 nBytes = FDH_READ(fdP, buf, size);
197 nt_iwrite(IHandle_t * h, int offset, char *buf, int size)
206 if (FDH_SEEK(fdP, offset, SEEK_SET) < 0) {
207 FDH_REALLYCLOSE(fdP);
210 nBytes = FDH_WRITE(fdP, buf, size);
219 BY_HANDLE_FILE_INFORMATION finfo;
221 if (!GetFileInformationByHandle(fd, &finfo))
224 return finfo.nFileSizeLow;
229 nt_getFileCreationTime(FD_t fd, FILETIME * ftime)
231 BY_HANDLE_FILE_INFORMATION finfo;
233 if (!GetFileInformationByHandle(fd, &finfo))
236 *ftime = finfo.ftCreationTime;
242 nt_setFileCreationTime(FD_t fd, FILETIME * ftime)
244 return !SetFileTime(fd, ftime, NULL, NULL);
256 cdrive = 'A' + (n - 1);
259 cdrive = _toupper(cdrive);
261 (void)sprintf(sdrive, "\\\\.\\%c:", cdrive);
262 drive_fd = nt_open(sdrive, O_RDWR, 0666);
263 if (drive_fd == INVALID_FD) {
267 if (!FlushFileBuffers((HANDLE) drive_fd)) {
268 errno = nterr_nt2unix(GetLastError(), EBADF);
277 /* Currently nt_ftruncate only tested to shrink a file. */
279 nt_ftruncate(FD_t fd, int len)
281 if (SetFilePointer(fd, (LONG) len, NULL, FILE_BEGIN)
283 errno = nterr_nt2unix(GetLastError(), EBADF);
286 if (!SetEndOfFile(fd)) {
287 errno = nterr_nt2unix(GetLastError(), EBADF);
297 int code = FlushFileBuffers(fd);
298 return code == 0 ? -1 : 0;
303 nt_seek(FD_t fd, int off, int where)
305 int code = SetFilePointer(fd, off, NULL, where);
310 /* Inode number format:
311 * low 32 bits - if a regular file or directory, the vnode. Else the type.
312 * 32-36 - unquifier tag and index into counts array for this vnode. Only
313 * two of the available bits are currently used. The rest are
314 * present in case we ever increase the number of types of volumes
315 * in the volume grou.
316 * bit 37 : 1 == special, 0 == regular
318 #define NT_VNODEMASK 0x00ffffffff
319 /* While the TAGMASK is 7, note that we are leaving 1 more bit available. */
320 #define NT_TAGMASK 0x7
321 #define NT_TAGSHIFT 32
322 #define NT_INODESPECIAL 0x2000000000
324 #define NT_MAXVOLS 5 /* Maximum supported number of volumes per volume
325 * group, not counting temporary (move) volumes.
326 * This is the number of separate files, all having
327 * the same vnode number, which can occur in a volume
332 int nt_SetLinkCount(FdHandle_t * h, Inode ino, int count, int locked);
336 * converts a device number (2-25) into a drive letter name.
339 * drive - assumes drive is a pointer to a string at least 3 bytes long.
340 * dev - drive number 2-25, since A-C already in use.
343 * Returns pointer to end of drive if successful, else NULL.
347 nt_DevToDrive(char *drive, int dev)
349 if (dev < 2 || dev > 25) {
351 return NULL; /* Invalid drive */
353 drive[0] = (char)('A' + dev);
361 /* Returns pointer to end of name if successful, else NULL. */
363 nt_HandleToVolDir(char *name, IHandle_t * h)
367 if (!(name = nt_DevToDrive(name, h->ih_dev)))
370 (void)memcpy(name, "\\Vol_", 5);
372 (void)strcpy(name, int_to_base32(str1, h->ih_vid));
373 name += strlen(name);
374 memcpy(name, ".data", 5);
383 * Constructs a file name for the fully qualified handle.
386 nt_HandleToName(char *name, IHandle_t * h)
389 int tag = (int)((h->ih_ino >> NT_TAGSHIFT) & NT_TAGMASK);
390 int vno = (int)(h->ih_ino & NT_VNODEMASK);
392 if (!(name = nt_HandleToVolDir(name, h)))
396 if (h->ih_ino & NT_INODESPECIAL)
402 str1[1] = ((vno & 0x1f) >> 1) + 'A';
405 memcpy(name, str1, 2);
407 (void)memcpy(name, "\\V_", 3);
409 (void)strcpy(name, int_to_base32(str1, vno));
410 name += strlen(name);
412 (void)strcpy(name, int_to_base32(str1, tag));
413 name += strlen(name);
419 /* nt_CreateDataDirectories
421 * The data for each volume is in a separate directory. The name of the
422 * volume is of the form: Vol_NNNNNN.data, where NNNNNN is a base 32
423 * representation of the RW volume ID (even where the RO is the only volume
424 * on the partition). Below that are separate subdirectories for the
425 * AFS directories and special files. There are also 16 directories for files,
426 * hashed on the low 5 bits (recall bit0 is always 0) of the vnode number.
427 * These directories are named:
428 * A - P - 16 file directories.
429 * Q ----- data directory
430 * R ----- special files directory
433 nt_CreateDataDirectories(IHandle_t * h, int *created)
439 if (!(s = nt_HandleToVolDir(name, h)))
442 if (mkdir(name) < 0) {
450 for (i = 'A'; i <= 'R'; i++) {
452 if (mkdir(name) < 0 && errno != EEXIST)
458 /* nt_RemoveDataDirectories
460 * Returns -1 on error. Typically, callers ignore this error bcause we
461 * can continue running if the removes fail. The salvage process will
462 * finish tidying up for us.
465 nt_RemoveDataDirectories(IHandle_t * h)
471 if (!(s = nt_HandleToVolDir(name, h)))
476 for (i = 'A'; i <= 'R'; i++) {
478 if (rmdir(name) < 0 && errno != ENOENT)
482 /* Delete the Vol_NNNNNN.data directory. */
485 if (rmdir(name) < 0 && errno != ENOENT) {
493 /* Create the file in the name space.
495 * Parameters stored as follows:
497 * p1 - volid - implied in containing directory.
498 * p2 - vnode - name is <vnode>.<tag> where tag is a file name unqiquifier.
499 * p3 - uniq -- creation time - dwHighDateTime
500 * p4 - dv ---- creation time - dwLowDateTime
502 * p1 - volid - creation time - dwHighDateTime
503 * p2 - vnode - -1 means special, file goes in "S" subdirectory.
504 * p3 - type -- name is <type>.<tag> where tag is a file name unqiquifier.
505 * p4 - parid - parent volume id - implied in containing directory.
507 * Return value is the inode number or (Inode)-1 if error.
508 * We "know" there is only one link table, so return EEXIST if there already
509 * is a link table. It's up to the calling code to test errno and increment
515 * This function is called by VCreateVolume to hide the implementation
516 * details of the inode numbers.
519 nt_MakeSpecIno(int type)
521 return ((Inode) type | (Inode) NT_INODESPECIAL);
525 nt_icreate(IHandle_t * h, char *part, int p1, int p2, int p3, int p4)
540 memset((void *)&tmp, 0, sizeof(IHandle_t));
543 tmp.ih_dev = tolower(*part) - 'a';
546 tmp.ih_vid = p4; /* Use parent volume id, where this file will be. */
548 if (nt_CreateDataDirectories(&tmp, &created_dir) < 0)
551 tmp.ih_ino = nt_MakeSpecIno(p3);
552 ftime.dwHighDateTime = p1;
553 ftime.dwLowDateTime = p2;
555 /* Regular file or directory.
556 * Encoding: p1 -> dir, p2 -> name, p3,p4 -> Create time
558 tmp.ih_ino = (Inode) p2;
561 ftime.dwHighDateTime = p3;
562 ftime.dwLowDateTime = p4;
565 /* Now create file. */
566 if ((code = nt_HandleToName(filename, &tmp)) < 0)
569 p = filename + strlen(filename);
571 for (i = 0; i < NT_MAXVOLS; i++) {
572 *p = *int_to_base32(str1, i);
573 fd = nt_open(filename, O_CREAT | O_RDWR | O_TRUNC | O_EXCL, 0666);
574 if (fd != INVALID_FD)
576 if (p2 == -1 && p3 == VI_LINKTABLE)
579 if (fd == INVALID_FD) {
584 tmp.ih_ino &= ~((Inode) NT_TAGMASK << NT_TAGSHIFT);
585 tmp.ih_ino |= ((Inode) i << NT_TAGSHIFT);
588 if (!SetFileTime((HANDLE) fd, &ftime, NULL, NULL)) {
596 if (fd == INVALID_FD) {
598 code = nt_unlink(filename);
609 code = nt_SetLinkCount(fdP, tmp.ih_ino, 1, 0);
611 } else if (p2 == -1 && p3 == VI_LINKTABLE) {
612 if (fd == INVALID_FD)
614 /* hack at tmp to setup for set link count call. */
616 code = nt_SetLinkCount(&tfd, (Inode) 0, 1, 0);
621 if (fd != INVALID_FD)
624 if (code && created_dir) {
626 nt_RemoveDataDirectories(&tmp);
629 return code ? (Inode) - 1 : tmp.ih_ino;
634 nt_iopen(IHandle_t * h)
639 /* Convert handle to file name. */
640 if (nt_HandleToName(name, h) < 0)
643 fd = nt_open(name, O_RDWR, 0666);
647 /* Need to detect vol special file and just unlink. In those cases, the
648 * handle passed in _is_ for the inode. We only check p1 for the special
652 nt_dec(IHandle_t * h, Inode ino, int p1)
659 if (ino & NT_INODESPECIAL) {
662 WIN32_FIND_DATA info;
665 /* Verify this is the right file. */
666 IH_INIT(tmp, h->ih_dev, h->ih_vid, ino);
668 if (nt_HandleToName(name, tmp) < 0) {
675 FindFirstFileEx(name, FindExInfoStandard, &info,
676 FindExSearchNameMatch, NULL,
677 FIND_FIRST_EX_CASE_SENSITIVE);
681 return -1; /* Can't get info, leave alone */
685 if (info.ftCreationTime.dwHighDateTime != (unsigned int)p1) {
690 /* If it's the link table itself, decrement the link count. */
691 if ((ino & NT_VNODEMASK) == VI_LINKTABLE) {
698 if ((count = nt_GetLinkCount(fdP, (Inode) 0, 1)) < 0) {
699 FDH_REALLYCLOSE(fdP);
705 if (nt_SetLinkCount(fdP, (Inode) 0, count < 0 ? 0 : count, 1) < 0) {
706 FDH_REALLYCLOSE(fdP);
711 FDH_REALLYCLOSE(fdP);
718 if ((code = nt_unlink(name)) == 0) {
719 if ((ino & NT_VNODEMASK) == VI_LINKTABLE) {
720 /* Try to remove directory. If it fails, that's ok.
721 * Salvage will clean up.
723 (void)nt_RemoveDataDirectories(tmp);
729 /* Get a file descriptor handle for this Inode */
735 if ((count = nt_GetLinkCount(fdP, ino, 1)) < 0) {
736 FDH_REALLYCLOSE(fdP);
742 if (nt_SetLinkCount(fdP, ino, count, 1) < 0) {
743 FDH_REALLYCLOSE(fdP);
750 nt_HandleToName(name, &th);
751 code = nt_unlink(name);
760 nt_inc(IHandle_t * h, Inode ino, int p1)
766 if (ino & NT_INODESPECIAL) {
767 if ((ino & NT_VNODEMASK) != VI_LINKTABLE)
772 /* Get a file descriptor handle for this Inode */
778 if ((count = nt_GetLinkCount(fdP, ino, 1)) < 0)
787 if (nt_SetLinkCount(fdP, ino, count, 1) < 0)
791 FDH_REALLYCLOSE(fdP);
800 /************************************************************************
801 * Link Table Organization
802 ************************************************************************
804 * The link table volume special file is used to hold the link counts that
805 * are held in the inodes in inode based AFS vice filesystems. Since NTFS
806 * doesn't provide us that access, the link counts are being kept in a separate
807 * volume special file. The file begins with the usual version stamp
808 * information and is then followed by one row per vnode number. vnode 0
809 * is used to hold the link count of the link table itself. That is because
810 * the same link table is shared among all the volumes of the volume group
811 * and is deleted only when the last volume of a volume group is deleted.
813 * Within each row, the columns are 3 bits wide. They can each hold a 0 based
814 * link count from 0 through 7. Each colume represents a unique instance of
815 * that vnode. Say we have a file shared between the RW and a RO and a
816 * different version of the file (or a different uniquifer) for the BU volume.
817 * Then one column would be holding the link count of 2 for the RW and RO
818 * and a different column would hold the link count of 1 for the BU volume.
819 * The column used is determined for NT by the uiquifier tag applied to
820 * generate a unique file name in the NTFS namespace. The file name is
821 * of the form "V_<vno>.<tag>" . And the <tag> is also the column number
824 #define LINKTABLE_WIDTH 2
825 #define LINKTABLE_SHIFT 1 /* log 2 = 1 */
828 nt_GetLCOffsetAndIndexFromIno(Inode ino, int *offset, int *index)
830 int toff = (int)(ino & NT_VNODEMASK);
831 int tindex = (int)((ino >> NT_TAGSHIFT) & NT_TAGMASK);
833 *offset = (toff << LINKTABLE_SHIFT) + 8; /* *2 + sizeof stamp */
834 *index = (tindex << 1) + tindex;
839 * If lockit is set, lock the file and leave it locked upon a successful
843 nt_GetLinkCountInternal(FdHandle_t * h, Inode ino, int lockit, int fixup)
845 unsigned short row = 0;
846 DWORD bytesRead, bytesWritten;
849 /* there's no linktable yet. the salvager will create one later */
850 if (h->fd_fd == INVALID_HANDLE_VALUE && fixup)
853 nt_GetLCOffsetAndIndexFromIno(ino, &offset, &index);
856 if (!LockFile(h->fd_fd, offset, 0, 2, 0))
860 if (!SetFilePointer(h->fd_fd, (LONG) offset, NULL, FILE_BEGIN))
861 goto bad_getLinkByte;
863 if (!ReadFile(h->fd_fd, (void *)&row, 2, &bytesRead, NULL))
864 goto bad_getLinkByte;
866 if (bytesRead == 0 && fixup) {
869 if (!GetFileSizeEx(h->fd_fd, &size) || size.QuadPart >= offset+sizeof(row))
870 goto bad_getLinkByte;
871 FDH_TRUNC(h, offset+sizeof(row));
874 WriteFile(h->fd_fd, (char *)&row, sizeof(row), &bytesWritten, NULL);
877 if (fixup && !((row >> index) & NT_TAGMASK)) {
882 return (int)((row >> index) & NT_TAGMASK);
886 UnlockFile(h->fd_fd, offset, 0, 2, 0);
891 nt_GetLinkCount(FdHandle_t * h, Inode ino, int lockit)
893 return nt_GetLinkCountInternal(h, ino, lockit, 0);
897 nt_SetNonZLC(FdHandle_t * h, Inode ino)
899 (void)nt_GetLinkCountInternal(h, ino, 0, 1);
904 * If locked is set, assume file is locked. Otherwise, lock file before
905 * proceeding to modify it.
908 nt_SetLinkCount(FdHandle_t * h, Inode ino, int count, int locked)
912 DWORD bytesRead, bytesWritten;
915 nt_GetLCOffsetAndIndexFromIno(ino, &offset, &index);
919 if (!LockFile(h->fd_fd, offset, 0, 2, 0)) {
920 errno = nterr_nt2unix(GetLastError(), EBADF);
924 if (!SetFilePointer(h->fd_fd, (LONG) offset, NULL, FILE_BEGIN)) {
925 errno = nterr_nt2unix(GetLastError(), EBADF);
926 goto bad_SetLinkCount;
930 if (!ReadFile(h->fd_fd, (void *)&row, 2, &bytesRead, NULL)) {
931 errno = nterr_nt2unix(GetLastError(), EBADF);
932 goto bad_SetLinkCount;
937 bytesRead = 7 << index;
939 row &= (unsigned short)~bytesRead;
940 row |= (unsigned short)count;
942 if (!SetFilePointer(h->fd_fd, (LONG) offset, NULL, FILE_BEGIN)) {
943 errno = nterr_nt2unix(GetLastError(), EBADF);
944 goto bad_SetLinkCount;
947 if (!WriteFile(h->fd_fd, (void *)&row, 2, &bytesWritten, NULL)) {
948 errno = nterr_nt2unix(GetLastError(), EBADF);
949 goto bad_SetLinkCount;
956 UnlockFile(h->fd_fd, offset, 0, 2, 0);
962 /* ListViceInodes - write inode data to a results file. */
963 static int DecodeInodeName(char *name, int *p1, int *p2);
964 static int DecodeVolumeName(char *name, int *vid);
965 static int nt_ListAFSSubDirs(IHandle_t * dirIH,
966 int (*write_fun) (FILE *, struct ViceInodeInfo *,
967 char *, char *), FILE * fp,
968 int (*judgeFun) (struct ViceInodeInfo *,
969 int vid, void *rock),
970 int singleVolumeNumber, void *rock);
975 * Write the inode data to the results file.
977 * Returns -2 on error, 0 on success.
979 * This is written as a callback simply so that other listing routines
980 * can use the same inode reading code.
983 WriteInodeInfo(FILE * fp, struct ViceInodeInfo *info, char *dir, char *name)
986 n = fwrite(info, sizeof(*info), 1, fp);
987 return (n == 1) ? 0 : -2;
992 * Fill the results file with the requested inode information.
996 * -1 - complete failure, salvage should terminate.
997 * -2 - not enough space on partition, salvager has error message for this.
999 * This code optimizes single volume salvages by just looking at that one
1000 * volume's directory.
1002 * If the resultFile is NULL, then don't call the write routine.
1005 ListViceInodes(char *devname, char *mountedOn, char *resultFile,
1006 int (*judgeInode) (struct ViceInodeInfo * info, int vid, void *rock),
1007 int singleVolumeNumber, int *forcep, int forceR, char *wpath,
1010 FILE *fp = (FILE *) - 1;
1015 fp = fopen(resultFile, "w");
1017 Log("Unable to create inode description file %s\n", resultFile);
1022 nt_ListAFSFiles(wpath, WriteInodeInfo, fp, judgeInode,
1023 singleVolumeNumber, rock);
1033 if (fflush(fp) == EOF) {
1034 Log("Unable to successfully flush inode file for %s\n", mountedOn);
1038 if (fsync(fileno(fp)) == -1) {
1039 Log("Unable to successfully fsync inode file for %s\n", mountedOn);
1043 if (fclose(fp) == EOF) {
1044 Log("Unable to successfully close inode file for %s\n", mountedOn);
1049 * Paranoia: check that the file is really the right size
1051 if (stat(resultFile, &status) == -1) {
1052 Log("Unable to successfully stat inode file for %s\n", mountedOn);
1055 if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
1056 Log("Wrong size (%d instead of %d) in inode file for %s\n",
1057 status.st_size, ninodes * sizeof(struct ViceInodeInfo),
1067 * Collect all the matching AFS files on the drive.
1068 * If singleVolumeNumber is non-zero, just return files for that volume.
1070 * Returns <0 on error, else number of files found to match.
1073 nt_ListAFSFiles(char *dev,
1074 int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
1076 int (*judgeFun) (struct ViceInodeInfo *, int, void *),
1077 int singleVolumeNumber, void *rock)
1080 char name[MAX_PATH];
1084 static void FreeZLCList(void);
1086 memset((void *)&h, 0, sizeof(IHandle_t));
1087 h.ih_dev = toupper(*dev) - 'A';
1089 if (singleVolumeNumber) {
1090 h.ih_vid = singleVolumeNumber;
1091 if (!nt_HandleToVolDir(name, &h))
1094 nt_ListAFSSubDirs(&h, writeFun, fp, judgeFun, singleVolumeNumber, rock);
1098 /* Find all Vol_*.data directories and descend through them. */
1099 if (!nt_DevToDrive(name, h.ih_dev))
1102 dirp = opendir(name);
1105 while (dp = readdir(dirp)) {
1106 if (!DecodeVolumeName(dp->d_name, &h.ih_vid)) {
1107 ninodes += nt_ListAFSSubDirs(&h, writeFun, fp, judgeFun, 0, rock);
1117 /* nt_ListAFSSubDirs
1119 * List the S, F, and D subdirectories of this volume's directory.
1123 * > = 0 - number of AFS files found.
1126 nt_ListAFSSubDirs(IHandle_t * dirIH,
1127 int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
1129 int (*judgeFun) (struct ViceInodeInfo *, int, void *),
1130 int singleVolumeNumber, void *rock)
1133 IHandle_t myIH = *dirIH;
1135 WIN32_FIND_DATA data;
1137 char basePath[1024];
1139 char findPath[1024];
1140 struct ViceInodeInfo info;
1142 FdHandle_t linkHandle;
1144 static void DeleteZLCFiles(char *path);
1146 s = nt_HandleToVolDir(path, &myIH);
1147 strcpy(basePath, path);
1154 /* Do the directory containing the special files first to pick up link
1157 for (i = 'R'; i >= 'A'; i--) {
1159 (void)strcpy(findPath, path);
1160 (void)strcat(findPath, "\\*");
1162 FindFirstFileEx(findPath, FindExInfoStandard, &data,
1163 FindExSearchNameMatch, NULL,
1164 FIND_FIRST_EX_CASE_SENSITIVE);
1165 if (dirH == INVALID_HANDLE_VALUE)
1168 /* Store the vice info. */
1169 memset((void *)&info, 0, sizeof(info));
1170 if (*data.cFileName == '.')
1172 if (DecodeInodeName(data.cFileName, &vno, &tag) < 0) {
1173 Log("Error parsing %s\\%s\n", path, data.cFileName);
1175 info.inodeNumber = (Inode) tag << NT_TAGSHIFT;
1176 info.inodeNumber |= (Inode) vno;
1177 info.byteCount = data.nFileSizeLow;
1179 if (i == 'R') { /* Special inode. */
1180 info.inodeNumber |= NT_INODESPECIAL;
1181 info.u.param[0] = data.ftCreationTime.dwHighDateTime;
1182 info.u.param[1] = data.ftCreationTime.dwLowDateTime;
1183 info.u.param[2] = vno;
1184 info.u.param[3] = dirIH->ih_vid;
1185 if (info.u.param[2] != VI_LINKTABLE) {
1188 /* Open this handle */
1190 (void)sprintf(lpath, "%s\\%s", path, data.cFileName);
1191 linkHandle.fd_fd = nt_open(lpath, O_RDONLY, 0666);
1193 nt_GetLinkCount(&linkHandle, (Inode) 0, 0);
1195 } else { /* regular file. */
1197 nt_GetLinkCount(&linkHandle, info.inodeNumber, 0);
1198 if (info.linkCount == 0) {
1200 Log("Found 0 link count file %s\\%s, deleting it.\n",
1201 path, data.cFileName);
1202 AddToZLCDeleteList((char)i, data.cFileName);
1204 Log("Found 0 link count file %s\\%s.\n", path,
1209 info.u.param[0] = dirIH->ih_vid;
1210 info.u.param[1] = vno;
1211 info.u.param[2] = data.ftCreationTime.dwHighDateTime;
1212 info.u.param[3] = data.ftCreationTime.dwLowDateTime;
1214 if (judgeFun && !(*judgeFun) (&info, singleVolumeNumber, rock))
1216 if ((*writeFun) (fp, &info, path, data.cFileName) < 0) {
1217 nt_close(linkHandle.fd_fd);
1224 if (!FindNextFile(dirH, &data)) {
1230 nt_close(linkHandle.fd_fd);
1231 DeleteZLCFiles(basePath);
1233 /* Then why does this directory exist? Blow it away. */
1234 nt_RemoveDataDirectories(dirIH);
1240 /* The name begins with "Vol_" and ends with .data. See nt_HandleToVolDir() */
1242 DecodeVolumeName(char *name, int *vid)
1250 if (strncmp(name, "Vol_", 4))
1252 if (strcmp(name + len - 5, ".data"))
1255 stmp[len - 5] = '\0';
1256 *vid = base32_to_int(stmp + 4);
1260 /* Recall that the name beings with a "V_" */
1262 DecodeInodeName(char *name, int *p1, int *p2)
1267 (void)strcpy(stmp, name);
1268 s = strrchr(stmp, '_');
1272 t = strrchr(s, '.');
1277 *p1 = base32_to_int(s);
1278 *p2 = base32_to_int(t + 1);
1285 * returns a static string used to print either 32 or 64 bit inode numbers.
1288 PrintInode(char *s, Inode ino)
1290 static afs_ino_str_t result;
1294 (void)sprintf((char *)s, "%I64u", ino);
1300 /* Routines to facilitate removing zero link count files. */
1301 #define MAX_ZLC_NAMES 32
1302 #define MAX_ZLC_NAMELEN 16
1303 typedef struct zlcList_s {
1304 struct zlcList_s *zlc_next;
1306 char zlc_names[MAX_ZLC_NAMES][MAX_ZLC_NAMELEN];
1309 static zlcList_t *zlcAnchor = NULL;
1310 static zlcList_t *zlcCur = NULL;
1313 AddToZLCDeleteList(char dir, char *name)
1315 assert(strlen(name) <= MAX_ZLC_NAMELEN - 3);
1317 if (!zlcCur || zlcCur->zlc_n >= MAX_ZLC_NAMES) {
1318 if (zlcCur && zlcCur->zlc_next)
1319 zlcCur = zlcCur->zlc_next;
1321 zlcList_t *tmp = (zlcList_t *) malloc(sizeof(zlcList_t));
1327 zlcCur->zlc_next = tmp;
1331 zlcCur->zlc_next = NULL;
1335 (void)sprintf(zlcCur->zlc_names[zlcCur->zlc_n], "%c\\%s", dir, name);
1340 DeleteZLCFiles(char *path)
1346 for (z = zlcAnchor; z; z = z->zlc_next) {
1347 for (i = 0; i < z->zlc_n; i++) {
1348 (void)sprintf(fname, "%s\\%s", path, z->zlc_names[i]);
1349 if (nt_unlink(fname) < 0) {
1350 Log("ZLC: Can't unlink %s, dos error = %d\n", fname,
1354 z->zlc_n = 0; /* Can reuse space. */
1367 tnext = i->zlc_next;
1371 zlcCur = zlcAnchor = NULL;
1374 #endif /* AFS_NT40_ENV */