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