6e0c59e546064b011bb11e1566f42c000eaaabae
[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
16 #ifdef AFS_NT40_ENV
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <direct.h>
22 #include <io.h>
23 #include <fcntl.h>
24 #include <sys/stat.h>
25 #include <windows.h>
26 #include <winnt.h>
27 #include <winbase.h>
28 #include <lock.h>
29 #include <afs/afsutil.h>
30 #include "nfs.h"
31 #include <afs/afsint.h>
32 #include "ihandle.h"
33 #include "vnode.h"
34 #include "volume.h"
35 #include "viceinode.h"
36 #include <dirent.h>
37 #include <afs/assert.h>
38 #include <afs/errmap_nt.h>
39
40 #define BASEFILEATTRIBUTE FILE_ATTRIBUTE_NORMAL
41
42 int Testing = 0;
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, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 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 static int
841 nt_GetLinkCountInternal(FdHandle_t * h, Inode ino, int lockit, int fixup)
842 {
843     unsigned short row = 0;
844     DWORD bytesRead, bytesWritten;
845     int offset, index;
846
847     /* there's no linktable yet. the salvager will create one later */
848     if (h->fd_fd == INVALID_HANDLE_VALUE && fixup)
849        return 1;
850
851     nt_GetLCOffsetAndIndexFromIno(ino, &offset, &index);
852
853     if (lockit) {
854         if (!LockFile(h->fd_fd, offset, 0, 2, 0))
855             return -1;
856     }
857
858     if (!SetFilePointer(h->fd_fd, (LONG) offset, NULL, FILE_BEGIN))
859         goto bad_getLinkByte;
860
861     if (!ReadFile(h->fd_fd, (void *)&row, 2, &bytesRead, NULL))
862         goto bad_getLinkByte;
863
864     if (bytesRead == 0 && fixup) {
865         LARGE_INTEGER size;
866
867         if (!GetFileSizeEx(h->fd_fd, &size) || size.QuadPart >= offset+sizeof(row))
868             goto bad_getLinkByte;
869         FDH_TRUNC(h, offset+sizeof(row));
870         row = 1 << index;
871       rewrite:
872         WriteFile(h->fd_fd, (char *)&row, sizeof(row), &bytesWritten, NULL);
873     }
874
875     if (fixup && !((row >> index) & NT_TAGMASK)) {
876         row |= 1<<index;
877         goto rewrite;
878     }
879
880     return (int)((row >> index) & NT_TAGMASK);
881
882   bad_getLinkByte:
883     if (lockit)
884         UnlockFile(h->fd_fd, offset, 0, 2, 0);
885     return -1;
886 }
887
888 int
889 nt_GetLinkCount(FdHandle_t * h, Inode ino, int lockit)
890 {
891     return nt_GetLinkCountInternal(h, ino, lockit, 0);
892 }
893
894 void
895 nt_SetNonZLC(FdHandle_t * h, Inode ino)
896 {
897     (void)nt_GetLinkCountInternal(h, ino, 0, 1);
898 }
899
900
901 /* nt_SetLinkCount
902  * If locked is set, assume file is locked. Otherwise, lock file before
903  * proceeding to modify it.
904  */
905 int
906 nt_SetLinkCount(FdHandle_t * h, Inode ino, int count, int locked)
907 {
908     int offset, index;
909     unsigned short row;
910     DWORD bytesRead, bytesWritten;
911     int code = -1;
912
913     nt_GetLCOffsetAndIndexFromIno(ino, &offset, &index);
914
915
916     if (!locked) {
917         if (!LockFile(h->fd_fd, offset, 0, 2, 0)) {
918             errno = nterr_nt2unix(GetLastError(), EBADF);
919             return -1;
920         }
921     }
922     if (!SetFilePointer(h->fd_fd, (LONG) offset, NULL, FILE_BEGIN)) {
923         errno = nterr_nt2unix(GetLastError(), EBADF);
924         goto bad_SetLinkCount;
925     }
926
927
928     if (!ReadFile(h->fd_fd, (void *)&row, 2, &bytesRead, NULL)) {
929         errno = nterr_nt2unix(GetLastError(), EBADF);
930         goto bad_SetLinkCount;
931     }
932     if (bytesRead == 0)
933         row = 0;
934
935     bytesRead = 7 << index;
936     count <<= index;
937     row &= (unsigned short)~bytesRead;
938     row |= (unsigned short)count;
939
940     if (!SetFilePointer(h->fd_fd, (LONG) offset, NULL, FILE_BEGIN)) {
941         errno = nterr_nt2unix(GetLastError(), EBADF);
942         goto bad_SetLinkCount;
943     }
944
945     if (!WriteFile(h->fd_fd, (void *)&row, 2, &bytesWritten, NULL)) {
946         errno = nterr_nt2unix(GetLastError(), EBADF);
947         goto bad_SetLinkCount;
948     }
949
950     code = 0;
951
952
953   bad_SetLinkCount:
954     UnlockFile(h->fd_fd, offset, 0, 2, 0);
955
956     return code;
957 }
958
959
960 /* ListViceInodes - write inode data to a results file. */
961 static int DecodeInodeName(char *name, int *p1, int *p2);
962 static int DecodeVolumeName(char *name, afs_uint32 *vid);
963 static int nt_ListAFSSubDirs(IHandle_t * dirIH,
964                              int (*write_fun) (FILE *, struct ViceInodeInfo *,
965                                                char *, char *), FILE * fp,
966                              int (*judgeFun) (struct ViceInodeInfo *,
967                                               afs_uint32 vid, void *rock),
968                              afs_uint32 singleVolumeNumber, void *rock);
969
970
971 /* WriteInodeInfo
972  *
973  * Write the inode data to the results file.
974  *
975  * Returns -2 on error, 0 on success.
976  *
977  * This is written as a callback simply so that other listing routines
978  * can use the same inode reading code.
979  */
980 static int
981 WriteInodeInfo(FILE * fp, struct ViceInodeInfo *info, char *dir, char *name)
982 {
983     int n;
984     n = fwrite(info, sizeof(*info), 1, fp);
985     return (n == 1) ? 0 : -2;
986 }
987
988
989 /* ListViceInodes
990  * Fill the results file with the requested inode information.
991  *
992  * Return values:
993  *  0 - success
994  * -1 - complete failure, salvage should terminate.
995  * -2 - not enough space on partition, salvager has error message for this.
996  *
997  * This code optimizes single volume salvages by just looking at that one
998  * volume's directory.
999  *
1000  * If the inodeFile is NULL, then don't call the write routine.
1001  */
1002 int
1003 ListViceInodes(char *devname, char *mountedOn, FILE *inodeFile,
1004                int (*judgeInode) (struct ViceInodeInfo * info, afs_uint32 vid, void *rock),
1005                afs_uint32 singleVolumeNumber, int *forcep, int forceR, char *wpath,
1006                void *rock)
1007 {
1008     int ninodes;
1009     struct stat status;
1010
1011     ninodes =
1012         nt_ListAFSFiles(wpath, WriteInodeInfo, inodeFile, judgeInode,
1013                         singleVolumeNumber, rock);
1014
1015     if (!inodeFile)
1016         return ninodes;
1017
1018     if (ninodes < 0) {
1019         return ninodes;
1020     }
1021
1022     if (fflush(inodeFile) == EOF) {
1023         Log("Unable to successfully flush inode file for %s\n", mountedOn);
1024         return -2;
1025     }
1026     if (fsync(fileno(inodeFile)) == -1) {
1027         Log("Unable to successfully fsync inode file for %s\n", mountedOn);
1028         return -2;
1029     }
1030
1031     /*
1032      * Paranoia:  check that the file is really the right size
1033      */
1034     if (fstat(fileno(inodeFile), &status) == -1) {
1035         Log("Unable to successfully stat inode file for %s\n", mountedOn);
1036         return -2;
1037     }
1038     if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
1039         Log("Wrong size (%d instead of %d) in inode file for %s\n",
1040             status.st_size, ninodes * sizeof(struct ViceInodeInfo),
1041             mountedOn);
1042         return -2;
1043     }
1044     return 0;
1045 }
1046
1047
1048 /* nt_ListAFSFiles
1049  *
1050  * Collect all the matching AFS files on the drive.
1051  * If singleVolumeNumber is non-zero, just return files for that volume.
1052  *
1053  * Returns <0 on error, else number of files found to match.
1054  */
1055 int
1056 nt_ListAFSFiles(char *dev,
1057                 int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
1058                                  char *), FILE * fp,
1059                 int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *),
1060                 afs_uint32 singleVolumeNumber, void *rock)
1061 {
1062     IHandle_t h;
1063     char name[MAX_PATH];
1064     int ninodes = 0;
1065     DIR *dirp;
1066     struct dirent *dp;
1067     static void FreeZLCList(void);
1068
1069     memset((void *)&h, 0, sizeof(IHandle_t));
1070     h.ih_dev = toupper(*dev) - 'A';
1071
1072     if (singleVolumeNumber) {
1073         h.ih_vid = singleVolumeNumber;
1074         if (!nt_HandleToVolDir(name, &h))
1075             return -1;
1076         ninodes =
1077             nt_ListAFSSubDirs(&h, writeFun, fp, judgeFun, singleVolumeNumber, rock);
1078         if (ninodes < 0)
1079             return ninodes;
1080     } else {
1081         /* Find all Vol_*.data directories and descend through them. */
1082         if (!nt_DevToDrive(name, h.ih_dev))
1083             return -1;
1084         ninodes = 0;
1085         dirp = opendir(name);
1086         if (!dirp)
1087             return -1;
1088         while (dp = readdir(dirp)) {
1089             if (!DecodeVolumeName(dp->d_name, &h.ih_vid)) {
1090                 ninodes += nt_ListAFSSubDirs(&h, writeFun, fp, judgeFun, 0, rock);
1091             }
1092         }
1093     }
1094     FreeZLCList();
1095     return ninodes;
1096 }
1097
1098
1099
1100 /* nt_ListAFSSubDirs
1101  *
1102  * List the S, F, and D subdirectories of this volume's directory.
1103  *
1104  * Return values:
1105  * < 0 - an error
1106  * > = 0 - number of AFS files found.
1107  */
1108 static int
1109 nt_ListAFSSubDirs(IHandle_t * dirIH,
1110                   int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
1111                                    char *), FILE * fp,
1112                   int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *),
1113                   afs_uint32 singleVolumeNumber, void *rock)
1114 {
1115     int i;
1116     IHandle_t myIH = *dirIH;
1117     HANDLE dirH;
1118     WIN32_FIND_DATA data;
1119     char path[1024];
1120     char basePath[1024];
1121     char *s;
1122     char findPath[1024];
1123     struct ViceInodeInfo info;
1124     int tag, vno;
1125     FdHandle_t linkHandle;
1126     int ninodes = 0;
1127     static void DeleteZLCFiles(char *path);
1128
1129     s = nt_HandleToVolDir(path, &myIH);
1130     strcpy(basePath, path);
1131     if (!s)
1132         return -1;
1133     *s = '\\';
1134     s++;
1135     *(s + 1) = '\0';
1136
1137     /* Do the directory containing the special files first to pick up link
1138      * counts.
1139      */
1140     for (i = 'R'; i >= 'A'; i--) {
1141         *s = (char)i;
1142         (void)strcpy(findPath, path);
1143         (void)strcat(findPath, "\\*");
1144         dirH =
1145             FindFirstFileEx(findPath, FindExInfoStandard, &data,
1146                             FindExSearchNameMatch, NULL,
1147                             FIND_FIRST_EX_CASE_SENSITIVE);
1148         if (dirH == INVALID_HANDLE_VALUE)
1149             continue;
1150         while (1) {
1151             /* Store the vice info. */
1152             memset((void *)&info, 0, sizeof(info));
1153             if (*data.cFileName == '.')
1154                 goto next_file;
1155             if (DecodeInodeName(data.cFileName, &vno, &tag) < 0) {
1156                 Log("Error parsing %s\\%s\n", path, data.cFileName);
1157             } else {
1158                 info.inodeNumber = (Inode) tag << NT_TAGSHIFT;
1159                 info.inodeNumber |= (Inode) vno;
1160                 info.byteCount = data.nFileSizeLow;
1161
1162                 if (i == 'R') { /* Special inode. */
1163                     info.inodeNumber |= NT_INODESPECIAL;
1164                     info.u.param[0] = data.ftCreationTime.dwHighDateTime;
1165                     info.u.param[1] = data.ftCreationTime.dwLowDateTime;
1166                     info.u.param[2] = vno;
1167                     info.u.param[3] = dirIH->ih_vid;
1168                     if (info.u.param[2] != VI_LINKTABLE) {
1169                         info.linkCount = 1;
1170                     } else {
1171                         /* Open this handle */
1172                         char lpath[1024];
1173                         (void)sprintf(lpath, "%s\\%s", path, data.cFileName);
1174                         linkHandle.fd_fd = nt_open(lpath, O_RDONLY, 0666);
1175                         info.linkCount =
1176                             nt_GetLinkCount(&linkHandle, (Inode) 0, 0);
1177                     }
1178                 } else {        /* regular file. */
1179                     info.linkCount =
1180                         nt_GetLinkCount(&linkHandle, info.inodeNumber, 0);
1181                     if (info.linkCount == 0) {
1182 #ifdef notdef
1183                         Log("Found 0 link count file %s\\%s, deleting it.\n",
1184                             path, data.cFileName);
1185                         AddToZLCDeleteList((char)i, data.cFileName);
1186 #else
1187                         Log("Found 0 link count file %s\\%s.\n", path,
1188                             data.cFileName);
1189 #endif
1190                         goto next_file;
1191                     }
1192                     info.u.param[0] = dirIH->ih_vid;
1193                     info.u.param[1] = vno;
1194                     info.u.param[2] = data.ftCreationTime.dwHighDateTime;
1195                     info.u.param[3] = data.ftCreationTime.dwLowDateTime;
1196                 }
1197                 if (judgeFun && !(*judgeFun) (&info, singleVolumeNumber, rock))
1198                     goto next_file;
1199                 if ((*writeFun) (fp, &info, path, data.cFileName) < 0) {
1200                     nt_close(linkHandle.fd_fd);
1201                     FindClose(dirH);
1202                     return -1;
1203                 }
1204                 ninodes++;
1205             }
1206           next_file:
1207             if (!FindNextFile(dirH, &data)) {
1208                 break;
1209             }
1210         }
1211         FindClose(dirH);
1212     }
1213     nt_close(linkHandle.fd_fd);
1214     DeleteZLCFiles(basePath);
1215     if (!ninodes) {
1216         /* Then why does this directory exist? Blow it away. */
1217         nt_RemoveDataDirectories(dirIH);
1218     }
1219
1220     return ninodes;
1221 }
1222
1223 /* The name begins with "Vol_" and ends with .data.  See nt_HandleToVolDir() */
1224 static int
1225 DecodeVolumeName(char *name, afs_uint32 *vid)
1226 {
1227     char stmp[32];
1228     int len;
1229
1230     len = strlen(name);
1231     if (len <= 9)
1232         return -1;
1233     if (strncmp(name, "Vol_", 4))
1234         return -1;
1235     if (strcmp(name + len - 5, ".data"))
1236         return -1;
1237     strcpy(stmp, name);
1238     stmp[len - 5] = '\0';
1239     *vid = base32_to_int(stmp + 4);
1240     return 0;
1241 }
1242
1243 /* Recall that the name beings with a "V_" */
1244 static int
1245 DecodeInodeName(char *name, int *p1, int *p2)
1246 {
1247     char *s, *t;
1248     char stmp[16];
1249
1250     (void)strcpy(stmp, name);
1251     s = strrchr(stmp, '_');
1252     if (!s)
1253         return -1;
1254     s++;
1255     t = strrchr(s, '.');
1256     if (!t)
1257         return -1;
1258
1259     *t = '\0';
1260     *p1 = base32_to_int(s);
1261     *p2 = base32_to_int(t + 1);
1262     return 0;
1263 }
1264
1265
1266 /* PrintInode
1267  *
1268  * returns a static string used to print either 32 or 64 bit inode numbers.
1269  */
1270 char *
1271 PrintInode(char *s, Inode ino)
1272 {
1273     static afs_ino_str_t result;
1274     if (!s)
1275         s = result;
1276
1277     (void)sprintf((char *)s, "%I64u", ino);
1278
1279     return (char *)s;
1280 }
1281
1282
1283 /* Routines to facilitate removing zero link count files. */
1284 #define MAX_ZLC_NAMES 32
1285 #define MAX_ZLC_NAMELEN 16
1286 typedef struct zlcList_s {
1287     struct zlcList_s *zlc_next;
1288     int zlc_n;
1289     char zlc_names[MAX_ZLC_NAMES][MAX_ZLC_NAMELEN];
1290 } zlcList_t;
1291
1292 static zlcList_t *zlcAnchor = NULL;
1293 static zlcList_t *zlcCur = NULL;
1294
1295 static void
1296 AddToZLCDeleteList(char dir, char *name)
1297 {
1298     assert(strlen(name) <= MAX_ZLC_NAMELEN - 3);
1299
1300     if (!zlcCur || zlcCur->zlc_n >= MAX_ZLC_NAMES) {
1301         if (zlcCur && zlcCur->zlc_next)
1302             zlcCur = zlcCur->zlc_next;
1303         else {
1304             zlcList_t *tmp = (zlcList_t *) malloc(sizeof(zlcList_t));
1305             if (!tmp)
1306                 return;
1307             if (!zlcAnchor) {
1308                 zlcAnchor = tmp;
1309             } else {
1310                 zlcCur->zlc_next = tmp;
1311             }
1312             zlcCur = tmp;
1313             zlcCur->zlc_n = 0;
1314             zlcCur->zlc_next = NULL;
1315         }
1316     }
1317
1318     (void)sprintf(zlcCur->zlc_names[zlcCur->zlc_n], "%c\\%s", dir, name);
1319     zlcCur->zlc_n++;
1320 }
1321
1322 static void
1323 DeleteZLCFiles(char *path)
1324 {
1325     zlcList_t *z;
1326     int i;
1327     char fname[1024];
1328
1329     for (z = zlcAnchor; z; z = z->zlc_next) {
1330         for (i = 0; i < z->zlc_n; i++) {
1331             (void)sprintf(fname, "%s\\%s", path, z->zlc_names[i]);
1332             if (nt_unlink(fname) < 0) {
1333                 Log("ZLC: Can't unlink %s, dos error = %d\n", fname,
1334                     GetLastError());
1335             }
1336         }
1337         z->zlc_n = 0;           /* Can reuse space. */
1338     }
1339     zlcCur = zlcAnchor;
1340 }
1341
1342 static void
1343 FreeZLCList(void)
1344 {
1345     zlcList_t *tnext;
1346     zlcList_t *i;
1347
1348     i = zlcAnchor;
1349     while (i) {
1350         tnext = i->zlc_next;
1351         free(i);
1352         i = tnext;
1353     }
1354     zlcCur = zlcAnchor = NULL;
1355 }
1356
1357 #endif /* AFS_NT40_ENV */