vol-osi-assert-20080401
[openafs.git] / src / vol / ntops.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 /* I/O operations for the Windows NT platforms. */
11
12 #include <afsconfig.h>
13 #include <afs/param.h>
14
15 RCSID
16     ("$Header$");
17
18 #ifdef AFS_NT40_ENV
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <direct.h>
24 #include <io.h>
25 #include <fcntl.h>
26 #include <sys/stat.h>
27 #include <windows.h>
28 #include <winnt.h>
29 #include <winbase.h>
30 #include <lock.h>
31 #include <afs/afsutil.h>
32 #include "nfs.h"
33 #include <afs/afsint.h>
34 #include "ihandle.h"
35 #include "vnode.h"
36 #include "volume.h"
37 #include "viceinode.h"
38 #include <dirent.h>
39 #include <afs/assert.h>
40 #include <afs/errmap_nt.h>
41
42 #define BASEFILEATTRIBUTE FILE_ATTRIBUTE_NORMAL
43
44 int Testing = 0;
45
46 static void AddToZLCDeleteList(char dir, char *name);
47
48 /* nt_unlink - unlink a case sensitive name.
49  *
50  * nt_unlink supports the nt_dec call.
51  *
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.
57  */
58 int
59 nt_unlink(char *name)
60 {
61     HANDLE fh;
62
63     fh = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
64                     FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
65                     NULL, OPEN_EXISTING,
66                     BASEFILEATTRIBUTE | FILE_FLAG_DELETE_ON_CLOSE |
67                     FILE_FLAG_POSIX_SEMANTICS, NULL);
68     if (fh != INVALID_HANDLE_VALUE)
69         CloseHandle(fh);
70     else {
71         errno = nterr_nt2unix(GetLastError(), ENOENT);
72         return -1;
73     }
74     return 0;
75 }
76
77 /* nt_open - open an NT handle for a file.
78  *
79  * Return Value:
80  *      the handle or -1 on error.
81  */
82 FD_t
83 nt_open(char *name, int flags, int mode)
84 {
85     HANDLE fh;
86     DWORD nt_access = 0;
87     DWORD nt_share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
88     DWORD nt_create = 0;
89     /* Really use the sequential one for data files, random for meta data. */
90     DWORD FandA = BASEFILEATTRIBUTE | FILE_FLAG_SEQUENTIAL_SCAN;
91
92     /* set access */
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;
97
98     /* set creation */
99     switch (flags & (O_CREAT | O_EXCL | O_TRUNC)) {
100     case 0:
101         nt_create = OPEN_EXISTING;
102         break;
103     case O_CREAT:
104         nt_create = OPEN_ALWAYS;
105         break;
106     case O_CREAT | O_TRUNC:
107         nt_create = CREATE_ALWAYS;
108         break;
109     case O_CREAT | O_EXCL:
110     case O_CREAT | O_EXCL | O_TRUNC:
111         nt_create = CREATE_NEW;
112         break;
113     case O_TRUNC:
114         nt_create = TRUNCATE_EXISTING;
115         break;
116     case O_TRUNC | O_EXCL:
117     case O_EXCL:
118     default:
119         errno = EINVAL;
120         return INVALID_FD;
121         break;
122     }
123
124     fh = CreateFile(name, nt_access, nt_share, NULL, nt_create, FandA, NULL);
125
126     if (fh == INVALID_HANDLE_VALUE) {
127         fh = INVALID_FD;
128         errno = nterr_nt2unix(GetLastError(), EBADF);
129     }
130     return fh;
131 }
132
133 int
134 nt_close(FD_t fd)
135 {
136     BOOL code;
137
138     code = CloseHandle(fd);
139     if (!code) {
140         errno = nterr_nt2unix(GetLastError(), EBADF);
141         return -1;
142     }
143     return 0;
144 }
145
146 int
147 nt_write(FD_t fd, char *buf, size_t size)
148 {
149     BOOL code;
150     DWORD nbytes;
151
152     code = WriteFile((HANDLE) fd, (void *)buf, (DWORD) size, &nbytes, NULL);
153
154     if (!code) {
155         errno = nterr_nt2unix(GetLastError(), EBADF);
156         return -1;
157     }
158     return (int)nbytes;
159 }
160
161 int
162 nt_read(FD_t fd, char *buf, size_t size)
163 {
164     BOOL code;
165     DWORD nbytes;
166
167     code = ReadFile((HANDLE) fd, (void *)buf, (DWORD) size, &nbytes, NULL);
168
169     if (!code) {
170         errno = nterr_nt2unix(GetLastError(), EBADF);
171         return -1;
172     }
173     return (int)nbytes;
174 }
175
176 int
177 nt_iread(IHandle_t * h, int offset, char *buf, int size)
178 {
179     int nBytes;
180     FdHandle_t *fdP;
181
182     fdP = IH_OPEN(h);
183     if (fdP == NULL)
184         return -1;
185
186     if (FDH_SEEK(fdP, offset, SEEK_SET) < 0) {
187         FDH_REALLYCLOSE(fdP);
188         return -1;
189     }
190
191     nBytes = FDH_READ(fdP, buf, size);
192     FDH_CLOSE(fdP);
193     return nBytes;
194 }
195
196 int
197 nt_iwrite(IHandle_t * h, int offset, char *buf, int size)
198 {
199     int nBytes;
200     FdHandle_t *fdP;
201
202     fdP = IH_OPEN(h);
203     if (fdP == NULL)
204         return -1;
205
206     if (FDH_SEEK(fdP, offset, SEEK_SET) < 0) {
207         FDH_REALLYCLOSE(fdP);
208         return -1;
209     }
210     nBytes = FDH_WRITE(fdP, buf, size);
211     FDH_CLOSE(fdP);
212     return nBytes;
213 }
214
215
216 int
217 nt_size(FD_t fd)
218 {
219     BY_HANDLE_FILE_INFORMATION finfo;
220
221     if (!GetFileInformationByHandle(fd, &finfo))
222         return -1;
223
224     return finfo.nFileSizeLow;
225 }
226
227
228 int
229 nt_getFileCreationTime(FD_t fd, FILETIME * ftime)
230 {
231     BY_HANDLE_FILE_INFORMATION finfo;
232
233     if (!GetFileInformationByHandle(fd, &finfo))
234         return -1;
235
236     *ftime = finfo.ftCreationTime;
237
238     return 0;
239 }
240
241 int
242 nt_setFileCreationTime(FD_t fd, FILETIME * ftime)
243 {
244     return !SetFileTime(fd, ftime, NULL, NULL);
245 }
246
247 int
248 nt_sync(int cdrive)
249 {
250     FD_t drive_fd;
251     char sdrive[32];
252     int n;
253
254     n = cdrive;
255     if (n <= 26) {
256         cdrive = 'A' + (n - 1);
257     }
258
259     cdrive = _toupper(cdrive);
260
261     (void)sprintf(sdrive, "\\\\.\\%c:", cdrive);
262     drive_fd = nt_open(sdrive, O_RDWR, 0666);
263     if (drive_fd == INVALID_FD) {
264         return -1;
265     }
266
267     if (!FlushFileBuffers((HANDLE) drive_fd)) {
268         errno = nterr_nt2unix(GetLastError(), EBADF);
269         nt_close(drive_fd);
270         return -1;
271     }
272     nt_close(drive_fd);
273     return 0;
274 }
275
276
277 /* Currently nt_ftruncate only tested to shrink a file. */
278 int
279 nt_ftruncate(FD_t fd, int len)
280 {
281     if (SetFilePointer(fd, (LONG) len, NULL, FILE_BEGIN)
282         == 0xffffffff) {
283         errno = nterr_nt2unix(GetLastError(), EBADF);
284         return -1;
285     }
286     if (!SetEndOfFile(fd)) {
287         errno = nterr_nt2unix(GetLastError(), EBADF);
288         return -1;
289     }
290     return 0;
291 }
292
293
294 int
295 nt_fsync(FD_t fd)
296 {
297     int code = FlushFileBuffers(fd);
298     return code == 0 ? -1 : 0;
299 }
300
301
302 int
303 nt_seek(FD_t fd, int off, int where)
304 {
305     int code = SetFilePointer(fd, off, NULL, where);
306     return code;
307 }
308
309
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
317  */
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
323
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
328                                  * group at once.
329                                  */
330
331
332 int nt_SetLinkCount(FdHandle_t * h, Inode ino, int count, int locked);
333
334
335 /* nt_DevToDrive 
336  * converts a device number (2-25) into a drive letter name.
337  *
338  * Arguments:
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.
341  *
342  * Return Value:
343  * Returns pointer to end of drive if successful, else NULL.
344  *
345  */
346 char *
347 nt_DevToDrive(char *drive, int dev)
348 {
349     if (dev < 2 || dev > 25) {
350         errno = EINVAL;
351         return NULL;            /* Invalid drive */
352     }
353     drive[0] = (char)('A' + dev);
354     drive[1] = ':';
355     drive[2] = '\0';
356
357     return drive + 2;
358
359 }
360
361 /* Returns pointer to end of name if successful, else NULL. */
362 char *
363 nt_HandleToVolDir(char *name, IHandle_t * h)
364 {
365     b32_string_t str1;
366
367     if (!(name = nt_DevToDrive(name, h->ih_dev)))
368         return NULL;
369
370     (void)memcpy(name, "\\Vol_", 5);
371     name += 5;
372     (void)strcpy(name, int_to_base32(str1, h->ih_vid));
373     name += strlen(name);
374     memcpy(name, ".data", 5);
375     name += 5;
376     *name = '\0';
377
378     return name;
379 }
380
381 /* nt_HandleToName
382  *
383  * Constructs a file name for the fully qualified handle.
384  */
385 int
386 nt_HandleToName(char *name, IHandle_t * h)
387 {
388     b32_string_t str1;
389     int tag = (int)((h->ih_ino >> NT_TAGSHIFT) & NT_TAGMASK);
390     int vno = (int)(h->ih_ino & NT_VNODEMASK);
391
392     if (!(name = nt_HandleToVolDir(name, h)))
393         return -1;
394
395     str1[0] = '\\';
396     if (h->ih_ino & NT_INODESPECIAL)
397         str1[1] = 'R';
398     else {
399         if (vno & 0x1)
400             str1[1] = 'Q';
401         else
402             str1[1] = ((vno & 0x1f) >> 1) + 'A';
403     }
404
405     memcpy(name, str1, 2);
406     name += 2;
407     (void)memcpy(name, "\\V_", 3);
408     name += 3;
409     (void)strcpy(name, int_to_base32(str1, vno));
410     name += strlen(name);
411     *(name++) = '.';
412     (void)strcpy(name, int_to_base32(str1, tag));
413     name += strlen(name);
414     *name = '\0';
415
416     return 0;
417 }
418
419 /* nt_CreateDataDirectories
420  *
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
431  */
432 static int
433 nt_CreateDataDirectories(IHandle_t * h, int *created)
434 {
435     char name[128];
436     char *s;
437     int i;
438
439     if (!(s = nt_HandleToVolDir(name, h)))
440         return -1;
441
442     if (mkdir(name) < 0) {
443         if (errno != EEXIST)
444             return -1;
445     } else
446         *created = 1;
447
448     *s++ = '\\';
449     *(s + 1) = '\0';
450     for (i = 'A'; i <= 'R'; i++) {
451         *s = (char)i;
452         if (mkdir(name) < 0 && errno != EEXIST)
453             return -1;
454     }
455     return 0;
456 }
457
458 /* nt_RemoveDataDirectories
459  *
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.
463  */
464 static int
465 nt_RemoveDataDirectories(IHandle_t * h)
466 {
467     char name[128];
468     char *s;
469     int i;
470
471     if (!(s = nt_HandleToVolDir(name, h)))
472         return -1;
473
474     *s++ = '\\';
475     *(s + 1) = '\0';
476     for (i = 'A'; i <= 'R'; i++) {
477         *s = (char)i;
478         if (rmdir(name) < 0 && errno != ENOENT)
479             return -1;
480     }
481
482     /* Delete the Vol_NNNNNN.data directory. */
483     s--;
484     *s = '\0';
485     if (rmdir(name) < 0 && errno != ENOENT) {
486         return -1;
487     }
488
489     return 0;
490 }
491
492
493 /* Create the file in the name space.
494  *
495  * Parameters stored as follows:
496  * Regular files:
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
501  * Special files:
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.
506  *
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
510  * the link count.
511  */
512
513 /* nt_MakeSpecIno
514  *
515  * This function is called by VCreateVolume to hide the implementation
516  * details of the inode numbers.
517  */
518 Inode
519 nt_MakeSpecIno(int type)
520 {
521     return ((Inode) type | (Inode) NT_INODESPECIAL);
522 }
523
524 Inode
525 nt_icreate(IHandle_t * h, char *part, int p1, int p2, int p3, int p4)
526 {
527     char filename[128];
528     b32_string_t str1;
529     char *p;
530     int i;
531     FD_t fd;
532     int created_dir = 0;
533     int code = 0;
534     FILETIME ftime;
535     IHandle_t tmp;
536     FdHandle_t *fdP;
537     FdHandle_t tfd;
538     int save_errno;
539
540     memset((void *)&tmp, 0, sizeof(IHandle_t));
541
542
543     tmp.ih_dev = tolower(*part) - 'a';
544
545     if (p2 == -1) {
546         tmp.ih_vid = p4;        /* Use parent volume id, where this file will be. */
547
548         if (nt_CreateDataDirectories(&tmp, &created_dir) < 0)
549             goto bad;
550
551         tmp.ih_ino = nt_MakeSpecIno(p3);
552         ftime.dwHighDateTime = p1;
553         ftime.dwLowDateTime = p2;
554     } else {
555         /* Regular file or directory.
556          * Encoding: p1 -> dir,  p2 -> name, p3,p4 -> Create time
557          */
558         tmp.ih_ino = (Inode) p2;
559         tmp.ih_vid = p1;
560
561         ftime.dwHighDateTime = p3;
562         ftime.dwLowDateTime = p4;
563     }
564
565     /* Now create file. */
566     if ((code = nt_HandleToName(filename, &tmp)) < 0)
567         goto bad;
568
569     p = filename + strlen(filename);
570     p--;
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)
575             break;
576         if (p2 == -1 && p3 == VI_LINKTABLE)
577             break;
578     }
579     if (fd == INVALID_FD) {
580         code = -1;
581         goto bad;
582     }
583
584     tmp.ih_ino &= ~((Inode) NT_TAGMASK << NT_TAGSHIFT);
585     tmp.ih_ino |= ((Inode) i << NT_TAGSHIFT);
586
587     if (!code) {
588         if (!SetFileTime((HANDLE) fd, &ftime, NULL, NULL)) {
589             errno = EBADF;
590             code = -1;
591         }
592     }
593
594     if (!code) {
595         if (p2 != -1) {
596             if (fd == INVALID_FD) {
597                 errno = ENOENT;
598                 code = nt_unlink(filename);
599                 if (code == -1) {
600                 }
601                 code = -1;
602                 goto bad;
603             }
604             fdP = IH_OPEN(h);
605             if (fdP == NULL) {
606                 code = -1;
607                 goto bad;
608             }
609             code = nt_SetLinkCount(fdP, tmp.ih_ino, 1, 0);
610             FDH_CLOSE(fdP);
611         } else if (p2 == -1 && p3 == VI_LINKTABLE) {
612             if (fd == INVALID_FD)
613                 goto bad;
614             /* hack at tmp to setup for set link count call. */
615             tfd.fd_fd = fd;
616             code = nt_SetLinkCount(&tfd, (Inode) 0, 1, 0);
617         }
618     }
619
620   bad:
621     if (fd != INVALID_FD)
622         nt_close(fd);
623
624     if (code && created_dir) {
625         save_errno = errno;
626         nt_RemoveDataDirectories(&tmp);
627         errno = save_errno;
628     }
629     return code ? (Inode) - 1 : tmp.ih_ino;
630 }
631
632
633 FD_t
634 nt_iopen(IHandle_t * h)
635 {
636     FD_t fd;
637     char name[128];
638
639     /* Convert handle to file name. */
640     if (nt_HandleToName(name, h) < 0)
641         return INVALID_FD;
642
643     fd = nt_open(name, O_RDWR, 0666);
644     return fd;
645 }
646
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
649  * files.
650  */
651 int
652 nt_dec(IHandle_t * h, Inode ino, int p1)
653 {
654     int count = 0;
655     char name[128];
656     int code = 0;
657     FdHandle_t *fdP;
658
659     if (ino & NT_INODESPECIAL) {
660         IHandle_t *tmp;
661         int was_closed = 0;
662         WIN32_FIND_DATA info;
663         HANDLE dirH;
664
665         /* Verify this is the right file. */
666         IH_INIT(tmp, h->ih_dev, h->ih_vid, ino);
667
668         if (nt_HandleToName(name, tmp) < 0) {
669             IH_RELEASE(tmp);
670             errno = EINVAL;
671             return -1;
672         }
673
674         dirH =
675             FindFirstFileEx(name, FindExInfoStandard, &info,
676                             FindExSearchNameMatch, NULL,
677                             FIND_FIRST_EX_CASE_SENSITIVE);
678         if (!dirH) {
679             IH_RELEASE(tmp);
680             errno = ENOENT;
681             return -1;          /* Can't get info, leave alone */
682         }
683
684         FindClose(dirH);
685         if (info.ftCreationTime.dwHighDateTime != (unsigned int)p1) {
686             IH_RELEASE(tmp);
687             return -1;
688         }
689
690         /* If it's the link table itself, decrement the link count. */
691         if ((ino & NT_VNODEMASK) == VI_LINKTABLE) {
692             fdP = IH_OPEN(tmp);
693             if (fdP == NULL) {
694                 IH_RELEASE(tmp);
695                 return -1;
696             }
697
698             if ((count = nt_GetLinkCount(fdP, (Inode) 0, 1)) < 0) {
699                 FDH_REALLYCLOSE(fdP);
700                 IH_RELEASE(tmp);
701                 return -1;
702             }
703
704             count--;
705             if (nt_SetLinkCount(fdP, (Inode) 0, count < 0 ? 0 : count, 1) < 0) {
706                 FDH_REALLYCLOSE(fdP);
707                 IH_RELEASE(tmp);
708                 return -1;
709             }
710
711             FDH_REALLYCLOSE(fdP);
712             if (count > 0) {
713                 IH_RELEASE(tmp);
714                 return 0;
715             }
716         }
717
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.
722                  */
723                 (void)nt_RemoveDataDirectories(tmp);
724             }
725         }
726
727         IH_RELEASE(tmp);
728     } else {
729         /* Get a file descriptor handle for this Inode */
730         fdP = IH_OPEN(h);
731         if (fdP == NULL) {
732             return -1;
733         }
734
735         if ((count = nt_GetLinkCount(fdP, ino, 1)) < 0) {
736             FDH_REALLYCLOSE(fdP);
737             return -1;
738         }
739
740         count--;
741         if (count >= 0) {
742             if (nt_SetLinkCount(fdP, ino, count, 1) < 0) {
743                 FDH_REALLYCLOSE(fdP);
744                 return -1;
745             }
746         }
747         if (count == 0) {
748             IHandle_t th = *h;
749             th.ih_ino = ino;
750             nt_HandleToName(name, &th);
751             code = nt_unlink(name);
752         }
753         FDH_CLOSE(fdP);
754     }
755
756     return code;
757 }
758
759 int
760 nt_inc(IHandle_t * h, Inode ino, int p1)
761 {
762     int count;
763     int code = 0;
764     FdHandle_t *fdP;
765
766     if (ino & NT_INODESPECIAL) {
767         if ((ino & NT_VNODEMASK) != VI_LINKTABLE)
768             return 0;
769         ino = (Inode) 0;
770     }
771
772     /* Get a file descriptor handle for this Inode */
773     fdP = IH_OPEN(h);
774     if (fdP == NULL) {
775         return -1;
776     }
777
778     if ((count = nt_GetLinkCount(fdP, ino, 1)) < 0)
779         code = -1;
780     else {
781         count++;
782         if (count > 7) {
783             errno = EINVAL;
784             code = -1;
785             count = 7;
786         }
787         if (nt_SetLinkCount(fdP, ino, count, 1) < 0)
788             code = -1;
789     }
790     if (code) {
791         FDH_REALLYCLOSE(fdP);
792     } else {
793         FDH_CLOSE(fdP);
794     }
795     return code;
796 }
797
798
799
800 /************************************************************************
801  *  Link Table Organization
802  ************************************************************************
803  *
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.
812  *
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
822  * in the link table.
823  */
824 #define LINKTABLE_WIDTH 2
825 #define LINKTABLE_SHIFT 1       /* log 2 = 1 */
826
827 static void
828 nt_GetLCOffsetAndIndexFromIno(Inode ino, int *offset, int *index)
829 {
830     int toff = (int)(ino & NT_VNODEMASK);
831     int tindex = (int)((ino >> NT_TAGSHIFT) & NT_TAGMASK);
832
833     *offset = (toff << LINKTABLE_SHIFT) + 8;    /* *2 + sizeof stamp */
834     *index = (tindex << 1) + tindex;
835 }
836
837
838 /* nt_GetLinkCount
839  * If lockit is set, lock the file and leave it locked upon a successful
840  * return.
841  */
842 static int
843 nt_GetLinkCountInternal(FdHandle_t * h, Inode ino, int lockit, int fixup)
844 {
845     unsigned short row = 0;
846     DWORD bytesRead, bytesWritten;
847     int offset, index;
848
849     /* there's no linktable yet. the salvager will create one later */
850     if (h->fd_fd == INVALID_HANDLE_VALUE && fixup)
851        return 1;
852
853     nt_GetLCOffsetAndIndexFromIno(ino, &offset, &index);
854
855     if (lockit) {
856         if (!LockFile(h->fd_fd, offset, 0, 2, 0))
857             return -1;
858     }
859
860     if (!SetFilePointer(h->fd_fd, (LONG) offset, NULL, FILE_BEGIN))
861         goto bad_getLinkByte;
862
863     if (!ReadFile(h->fd_fd, (void *)&row, 2, &bytesRead, NULL)) 
864         goto bad_getLinkByte;
865     
866     if (bytesRead == 0 && fixup) { 
867         LARGE_INTEGER size;
868
869         if (!GetFileSizeEx(h->fd_fd, &size) || size.QuadPart >= offset+sizeof(row))
870             goto bad_getLinkByte;
871         FDH_TRUNC(h, offset+sizeof(row));
872         row = 1 << index;
873       rewrite:
874         WriteFile(h->fd_fd, (char *)&row, sizeof(row), &bytesWritten, NULL);
875     }
876
877     if (fixup && !((row >> index) & NT_TAGMASK)) {
878         row |= 1<<index;
879         goto rewrite;
880     }
881  
882     return (int)((row >> index) & NT_TAGMASK);
883
884   bad_getLinkByte:
885     if (lockit)
886         UnlockFile(h->fd_fd, offset, 0, 2, 0);
887     return -1;
888 }
889
890 int
891 nt_GetLinkCount(FdHandle_t * h, Inode ino, int lockit)
892 {
893     return nt_GetLinkCountInternal(h, ino, lockit, 0);
894 }
895
896 void
897 nt_SetNonZLC(FdHandle_t * h, Inode ino) 
898 {
899     (void)nt_GetLinkCountInternal(h, ino, 0, 1);
900 }
901
902
903 /* nt_SetLinkCount
904  * If locked is set, assume file is locked. Otherwise, lock file before
905  * proceeding to modify it.
906  */
907 int
908 nt_SetLinkCount(FdHandle_t * h, Inode ino, int count, int locked)
909 {
910     int offset, index;
911     unsigned short row;
912     DWORD bytesRead, bytesWritten;
913     int code = -1;
914
915     nt_GetLCOffsetAndIndexFromIno(ino, &offset, &index);
916
917
918     if (!locked) {
919         if (!LockFile(h->fd_fd, offset, 0, 2, 0)) {
920             errno = nterr_nt2unix(GetLastError(), EBADF);
921             return -1;
922         }
923     }
924     if (!SetFilePointer(h->fd_fd, (LONG) offset, NULL, FILE_BEGIN)) {
925         errno = nterr_nt2unix(GetLastError(), EBADF);
926         goto bad_SetLinkCount;
927     }
928
929
930     if (!ReadFile(h->fd_fd, (void *)&row, 2, &bytesRead, NULL)) {
931         errno = nterr_nt2unix(GetLastError(), EBADF);
932         goto bad_SetLinkCount;
933     }
934     if (bytesRead == 0)
935         row = 0;
936
937     bytesRead = 7 << index;
938     count <<= index;
939     row &= (unsigned short)~bytesRead;
940     row |= (unsigned short)count;
941
942     if (!SetFilePointer(h->fd_fd, (LONG) offset, NULL, FILE_BEGIN)) {
943         errno = nterr_nt2unix(GetLastError(), EBADF);
944         goto bad_SetLinkCount;
945     }
946
947     if (!WriteFile(h->fd_fd, (void *)&row, 2, &bytesWritten, NULL)) {
948         errno = nterr_nt2unix(GetLastError(), EBADF);
949         goto bad_SetLinkCount;
950     }
951
952     code = 0;
953
954
955   bad_SetLinkCount:
956     UnlockFile(h->fd_fd, offset, 0, 2, 0);
957
958     return code;
959 }
960
961
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);
971
972
973 /* WriteInodeInfo
974  *
975  * Write the inode data to the results file. 
976  *
977  * Returns -2 on error, 0 on success.
978  *
979  * This is written as a callback simply so that other listing routines
980  * can use the same inode reading code.
981  */
982 static int
983 WriteInodeInfo(FILE * fp, struct ViceInodeInfo *info, char *dir, char *name)
984 {
985     int n;
986     n = fwrite(info, sizeof(*info), 1, fp);
987     return (n == 1) ? 0 : -2;
988 }
989
990
991 /* ListViceInodes
992  * Fill the results file with the requested inode information.
993  *
994  * Return values:
995  *  0 - success
996  * -1 - complete failure, salvage should terminate.
997  * -2 - not enough space on partition, salvager has error message for this.
998  *
999  * This code optimizes single volume salvages by just looking at that one
1000  * volume's directory. 
1001  *
1002  * If the resultFile is NULL, then don't call the write routine.
1003  */
1004 int
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, 
1008                void *rock)
1009 {
1010     FILE *fp = (FILE *) - 1;
1011     int ninodes;
1012     struct stat status;
1013
1014     if (resultFile) {
1015         fp = fopen(resultFile, "w");
1016         if (!fp) {
1017             Log("Unable to create inode description file %s\n", resultFile);
1018             return -1;
1019         }
1020     }
1021     ninodes =
1022         nt_ListAFSFiles(wpath, WriteInodeInfo, fp, judgeInode,
1023                         singleVolumeNumber, rock);
1024
1025     if (!resultFile)
1026         return ninodes;
1027
1028     if (ninodes < 0) {
1029         fclose(fp);
1030         return ninodes;
1031     }
1032
1033     if (fflush(fp) == EOF) {
1034         Log("Unable to successfully flush inode file for %s\n", mountedOn);
1035         fclose(fp);
1036         return -2;
1037     }
1038     if (fsync(fileno(fp)) == -1) {
1039         Log("Unable to successfully fsync inode file for %s\n", mountedOn);
1040         fclose(fp);
1041         return -2;
1042     }
1043     if (fclose(fp) == EOF) {
1044         Log("Unable to successfully close inode file for %s\n", mountedOn);
1045         return -2;
1046     }
1047
1048     /*
1049      * Paranoia:  check that the file is really the right size
1050      */
1051     if (stat(resultFile, &status) == -1) {
1052         Log("Unable to successfully stat inode file for %s\n", mountedOn);
1053         return -2;
1054     }
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),
1058             mountedOn);
1059         return -2;
1060     }
1061     return 0;
1062 }
1063
1064
1065 /* nt_ListAFSFiles
1066  *
1067  * Collect all the matching AFS files on the drive.
1068  * If singleVolumeNumber is non-zero, just return files for that volume.
1069  *
1070  * Returns <0 on error, else number of files found to match.
1071  */
1072 int
1073 nt_ListAFSFiles(char *dev,
1074                 int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
1075                                  char *), FILE * fp,
1076                 int (*judgeFun) (struct ViceInodeInfo *, int, void *),
1077                 int singleVolumeNumber, void *rock)
1078 {
1079     IHandle_t h;
1080     char name[MAX_PATH];
1081     int ninodes = 0;
1082     DIR *dirp;
1083     struct dirent *dp;
1084     static void FreeZLCList(void);
1085
1086     memset((void *)&h, 0, sizeof(IHandle_t));
1087     h.ih_dev = toupper(*dev) - 'A';
1088
1089     if (singleVolumeNumber) {
1090         h.ih_vid = singleVolumeNumber;
1091         if (!nt_HandleToVolDir(name, &h))
1092             return -1;
1093         ninodes =
1094             nt_ListAFSSubDirs(&h, writeFun, fp, judgeFun, singleVolumeNumber, rock);
1095         if (ninodes < 0)
1096             return ninodes;
1097     } else {
1098         /* Find all Vol_*.data directories and descend through them. */
1099         if (!nt_DevToDrive(name, h.ih_dev))
1100             return -1;
1101         ninodes = 0;
1102         dirp = opendir(name);
1103         if (!dirp)
1104             return -1;
1105         while (dp = readdir(dirp)) {
1106             if (!DecodeVolumeName(dp->d_name, &h.ih_vid)) {
1107                 ninodes += nt_ListAFSSubDirs(&h, writeFun, fp, judgeFun, 0, rock);
1108             }
1109         }
1110     }
1111     FreeZLCList();
1112     return ninodes;
1113 }
1114
1115
1116
1117 /* nt_ListAFSSubDirs
1118  *
1119  * List the S, F, and D subdirectories of this volume's directory.
1120  *
1121  * Return values:
1122  * < 0 - an error
1123  * > = 0 - number of AFS files found.
1124  */
1125 static int
1126 nt_ListAFSSubDirs(IHandle_t * dirIH,
1127                   int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
1128                                    char *), FILE * fp,
1129                   int (*judgeFun) (struct ViceInodeInfo *, int, void *),
1130                   int singleVolumeNumber, void *rock)
1131 {
1132     int i;
1133     IHandle_t myIH = *dirIH;
1134     HANDLE dirH;
1135     WIN32_FIND_DATA data;
1136     char path[1024];
1137     char basePath[1024];
1138     char *s;
1139     char findPath[1024];
1140     struct ViceInodeInfo info;
1141     int tag, vno;
1142     FdHandle_t linkHandle;
1143     int ninodes = 0;
1144     static void DeleteZLCFiles(char *path);
1145
1146     s = nt_HandleToVolDir(path, &myIH);
1147     strcpy(basePath, path);
1148     if (!s)
1149         return -1;
1150     *s = '\\';
1151     s++;
1152     *(s + 1) = '\0';
1153
1154     /* Do the directory containing the special files first to pick up link
1155      * counts.
1156      */
1157     for (i = 'R'; i >= 'A'; i--) {
1158         *s = (char)i;
1159         (void)strcpy(findPath, path);
1160         (void)strcat(findPath, "\\*");
1161         dirH =
1162             FindFirstFileEx(findPath, FindExInfoStandard, &data,
1163                             FindExSearchNameMatch, NULL,
1164                             FIND_FIRST_EX_CASE_SENSITIVE);
1165         if (dirH == INVALID_HANDLE_VALUE)
1166             continue;
1167         while (1) {
1168             /* Store the vice info. */
1169             memset((void *)&info, 0, sizeof(info));
1170             if (*data.cFileName == '.')
1171                 goto next_file;
1172             if (DecodeInodeName(data.cFileName, &vno, &tag) < 0) {
1173                 Log("Error parsing %s\\%s\n", path, data.cFileName);
1174             } else {
1175                 info.inodeNumber = (Inode) tag << NT_TAGSHIFT;
1176                 info.inodeNumber |= (Inode) vno;
1177                 info.byteCount = data.nFileSizeLow;
1178
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) {
1186                         info.linkCount = 1;
1187                     } else {
1188                         /* Open this handle */
1189                         char lpath[1024];
1190                         (void)sprintf(lpath, "%s\\%s", path, data.cFileName);
1191                         linkHandle.fd_fd = nt_open(lpath, O_RDONLY, 0666);
1192                         info.linkCount =
1193                             nt_GetLinkCount(&linkHandle, (Inode) 0, 0);
1194                     }
1195                 } else {        /* regular file. */
1196                     info.linkCount =
1197                         nt_GetLinkCount(&linkHandle, info.inodeNumber, 0);
1198                     if (info.linkCount == 0) {
1199 #ifdef notdef
1200                         Log("Found 0 link count file %s\\%s, deleting it.\n",
1201                             path, data.cFileName);
1202                         AddToZLCDeleteList((char)i, data.cFileName);
1203 #else
1204                         Log("Found 0 link count file %s\\%s.\n", path,
1205                             data.cFileName);
1206 #endif
1207                         goto next_file;
1208                     }
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;
1213                 }
1214                 if (judgeFun && !(*judgeFun) (&info, singleVolumeNumber, rock))
1215                     goto next_file;
1216                 if ((*writeFun) (fp, &info, path, data.cFileName) < 0) {
1217                     nt_close(linkHandle.fd_fd);
1218                     FindClose(dirH);
1219                     return -1;
1220                 }
1221                 ninodes++;
1222             }
1223           next_file:
1224             if (!FindNextFile(dirH, &data)) {
1225                 break;
1226             }
1227         }
1228         FindClose(dirH);
1229     }
1230     nt_close(linkHandle.fd_fd);
1231     DeleteZLCFiles(basePath);
1232     if (!ninodes) {
1233         /* Then why does this directory exist? Blow it away. */
1234         nt_RemoveDataDirectories(dirIH);
1235     }
1236
1237     return ninodes;
1238 }
1239
1240 /* The name begins with "Vol_" and ends with .data.  See nt_HandleToVolDir() */
1241 static int
1242 DecodeVolumeName(char *name, int *vid)
1243 {
1244     char stmp[32];
1245     int len;
1246
1247     len = strlen(name);
1248     if (len <= 9)
1249         return -1;
1250     if (strncmp(name, "Vol_", 4))
1251         return -1;
1252     if (strcmp(name + len - 5, ".data"))
1253         return -1;
1254     strcpy(stmp, name);
1255     stmp[len - 5] = '\0';
1256     *vid = base32_to_int(stmp + 4);
1257     return 0;
1258 }
1259
1260 /* Recall that the name beings with a "V_" */
1261 static int
1262 DecodeInodeName(char *name, int *p1, int *p2)
1263 {
1264     char *s, *t;
1265     char stmp[16];
1266
1267     (void)strcpy(stmp, name);
1268     s = strrchr(stmp, '_');
1269     if (!s)
1270         return -1;
1271     s++;
1272     t = strrchr(s, '.');
1273     if (!t)
1274         return -1;
1275
1276     *t = '\0';
1277     *p1 = base32_to_int(s);
1278     *p2 = base32_to_int(t + 1);
1279     return 0;
1280 }
1281
1282
1283 /* PrintInode
1284  *
1285  * returns a static string used to print either 32 or 64 bit inode numbers.
1286  */
1287 char *
1288 PrintInode(char *s, Inode ino)
1289 {
1290     static afs_ino_str_t result;
1291     if (!s)
1292         s = result;
1293
1294     (void)sprintf((char *)s, "%I64u", ino);
1295
1296     return (char *)s;
1297 }
1298
1299
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;
1305     int zlc_n;
1306     char zlc_names[MAX_ZLC_NAMES][MAX_ZLC_NAMELEN];
1307 } zlcList_t;
1308
1309 static zlcList_t *zlcAnchor = NULL;
1310 static zlcList_t *zlcCur = NULL;
1311
1312 static void
1313 AddToZLCDeleteList(char dir, char *name)
1314 {
1315     assert(strlen(name) <= MAX_ZLC_NAMELEN - 3);
1316
1317     if (!zlcCur || zlcCur->zlc_n >= MAX_ZLC_NAMES) {
1318         if (zlcCur && zlcCur->zlc_next)
1319             zlcCur = zlcCur->zlc_next;
1320         else {
1321             zlcList_t *tmp = (zlcList_t *) malloc(sizeof(zlcList_t));
1322             if (!tmp)
1323                 return;
1324             if (!zlcAnchor) {
1325                 zlcAnchor = tmp;
1326             } else {
1327                 zlcCur->zlc_next = tmp;
1328             }
1329             zlcCur = tmp;
1330             zlcCur->zlc_n = 0;
1331             zlcCur->zlc_next = NULL;
1332         }
1333     }
1334
1335     (void)sprintf(zlcCur->zlc_names[zlcCur->zlc_n], "%c\\%s", dir, name);
1336     zlcCur->zlc_n++;
1337 }
1338
1339 static void
1340 DeleteZLCFiles(char *path)
1341 {
1342     zlcList_t *z;
1343     int i;
1344     char fname[1024];
1345
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,
1351                     GetLastError());
1352             }
1353         }
1354         z->zlc_n = 0;           /* Can reuse space. */
1355     }
1356     zlcCur = zlcAnchor;
1357 }
1358
1359 static void
1360 FreeZLCList(void)
1361 {
1362     zlcList_t *tnext;
1363     zlcList_t *i;
1364
1365     i = zlcAnchor;
1366     while (i) {
1367         tnext = i->zlc_next;
1368         free(i);
1369         i = tnext;
1370     }
1371     zlcCur = zlcAnchor = NULL;
1372 }
1373
1374 #endif /* AFS_NT40_ENV */