726203720b3255487c8cbd909d5646a652056dbc
[openafs.git] / src / vol / namei_ops.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 Unix open by name (namei) interface. */
11
12 #include <afsconfig.h>
13 #include <afs/param.h>
14
15
16 #ifdef AFS_NAMEI_ENV
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <sys/stat.h>
23 #include <dirent.h>
24 #include <afs/afs_assert.h>
25 #include <string.h>
26 #include <sys/file.h>
27 #include <sys/param.h>
28 #include <lock.h>
29 #if defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV)
30 #include <unistd.h>
31 #endif
32 #include <afs/afsutil.h>
33 #include <lwp.h>
34 #include "nfs.h"
35 #include <afs/afsint.h>
36 #include "ihandle.h"
37 #include "vnode.h"
38 #include "volume.h"
39 #include "viceinode.h"
40 #include "voldefs.h"
41 #include "partition.h"
42 #include "fssync.h"
43 #include "volume_inline.h"
44 #include "common.h"
45 #include <afs/errors.h>
46
47 /*@+fcnmacros +macrofcndecl@*/
48 #ifdef O_LARGEFILE
49 #ifdef S_SPLINT_S
50 #endif /*S_SPLINT_S */
51 #define afs_stat                stat64
52 #define afs_fstat               fstat64
53 #define afs_open                open64
54 #define afs_fopen               fopen64
55 #else /* !O_LARGEFILE */
56 #ifdef S_SPLINT_S
57 #endif /*S_SPLINT_S */
58 #define afs_stat                stat
59 #define afs_fstat               fstat
60 #define afs_open                open
61 #define afs_fopen               fopen
62 #endif /* !O_LARGEFILE */
63 /*@=fcnmacros =macrofcndecl@*/
64
65 #ifndef LOCK_SH
66 #define   LOCK_SH   1    /* shared lock */
67 #define   LOCK_EX   2    /* exclusive lock */
68 #define   LOCK_NB   4    /* don't block when locking */
69 #define   LOCK_UN   8    /* unlock */
70 #endif
71
72 #ifdef AFS_SALSRV_ENV
73 #include <pthread.h>
74 #include <afs/work_queue.h>
75 #include <afs/thread_pool.h>
76 #include <vol/vol-salvage.h>
77 #endif
78
79 #ifndef HAVE_FLOCK
80 #include <fcntl.h>
81
82 /*
83  * This function emulates a subset of flock()
84  */
85 int
86 emul_flock(int fd, int cmd)
87 {    struct flock f;
88
89     memset(&f, 0, sizeof (f));
90
91     if (cmd & LOCK_UN)
92         f.l_type = F_UNLCK;
93     if (cmd & LOCK_SH)
94         f.l_type = F_RDLCK;
95     if (cmd & LOCK_EX)
96         f.l_type = F_WRLCK;
97
98     return fcntl(fd, (cmd & LOCK_NB) ? F_SETLK : F_SETLKW, &f);
99 }
100
101 #define flock(f,c)      emul_flock(f,c)
102 #endif
103
104 int Testing=0;
105
106
107 afs_sfsize_t
108 namei_iread(IHandle_t * h, afs_foff_t offset, char *buf, afs_fsize_t size)
109 {
110     afs_sfsize_t nBytes;
111     FdHandle_t *fdP;
112
113     fdP = IH_OPEN(h);
114     if (fdP == NULL)
115         return -1;
116
117     nBytes = FDH_PREAD(fdP, buf, size, offset);
118     FDH_CLOSE(fdP);
119     return nBytes;
120 }
121
122 afs_sfsize_t
123 namei_iwrite(IHandle_t * h, afs_foff_t offset, char *buf, afs_fsize_t size)
124 {
125     afs_sfsize_t nBytes;
126     FdHandle_t *fdP;
127
128     fdP = IH_OPEN(h);
129     if (fdP == NULL)
130         return -1;
131
132     nBytes = FDH_PWRITE(fdP, buf, size, offset);
133     FDH_CLOSE(fdP);
134     return nBytes;
135 }
136
137
138
139 /* Inode number format:
140  * low 26 bits - vnode number - all 1's if volume special file.
141  * next 3 bits - tag
142  * next 3 bits spare (0's)
143  * high 32 bits - uniquifier (regular) or type if spare
144  */
145 #define NAMEI_VNODEMASK    0x003ffffff
146 #define NAMEI_TAGMASK      0x7
147 #define NAMEI_TAGSHIFT     26
148 #define NAMEI_UNIQMASK     0xffffffff
149 #define NAMEI_UNIQSHIFT    32
150 #define NAMEI_INODESPECIAL ((Inode)NAMEI_VNODEMASK)
151 #define NAMEI_VNODESPECIAL NAMEI_VNODEMASK
152
153 /* dir1 is the high 8 bits of the 26 bit vnode */
154 #define VNO_DIR1(vno) ((vno >> 14) & 0xff)
155 /* dir2 is the next 9 bits */
156 #define VNO_DIR2(vno) ((vno >> 9) & 0x1ff)
157 /* "name" is the low 9 bits of the vnode, the 3 bit tag and the uniq */
158
159 #define NAMEI_SPECDIR "special"
160 #define NAMEI_SPECDIRLEN (sizeof(NAMEI_SPECDIR)-1)
161
162 #define NAMEI_MAXVOLS 5         /* Maximum supported number of volumes per volume
163                                  * group, not counting temporary (move) volumes.
164                                  * This is the number of separate files, all having
165                                  * the same vnode number, which can occur in a volume
166                                  * group at once.
167                                  */
168
169
170 typedef struct {
171     int ogm_owner;
172     int ogm_group;
173     int ogm_mode;
174 } namei_ogm_t;
175
176 static int namei_GetLinkCount2(FdHandle_t * h, Inode ino, int lockit, int fixup, int nowrite);
177
178 static int GetFreeTag(IHandle_t * ih, int vno);
179
180 /* namei_HandleToInodeDir
181  *
182  * Construct the path name of the directory holding the inode data.
183  * Format: /<vicepx>/INODEDIR
184  *
185  */
186 #define PNAME_BLEN 64
187 static void
188 namei_HandleToInodeDir(namei_t * name, IHandle_t * ih)
189 {
190     size_t offset;
191
192     memset(name, '\0', sizeof(*name));
193
194     /*
195      * Add the /vicepXX string to the start of name->n_base and then calculate
196      * offset as the number of bytes we know we added.
197      *
198      * FIXME: This embeds knowledge of the vice partition naming scheme and
199      * mapping from device numbers.  There needs to be an API that tells us
200      * this offset.
201      */
202     volutil_PartitionName_r(ih->ih_dev, name->n_base, sizeof(name->n_base));
203     offset = VICE_PREFIX_SIZE + (ih->ih_dev > 25 ? 2 : 1);
204     name->n_base[offset] = '/';
205     offset++;
206     strlcpy(name->n_base + offset, INODEDIR, sizeof(name->n_base) - offset);
207     strlcpy(name->n_path, name->n_base, sizeof(name->n_path));
208 }
209
210 #define addtoname(N, C)                                 \
211 do {                                                    \
212     strlcat((N)->n_path, "/", sizeof((N)->n_path));     \
213     strlcat((N)->n_path, (C), sizeof((N)->n_path));     \
214 } while(0)
215
216
217 static void
218 namei_HandleToVolDir(namei_t * name, IHandle_t * ih)
219 {
220     lb64_string_t tmp;
221
222     namei_HandleToInodeDir(name, ih);
223     (void)int32_to_flipbase64(tmp, (int64_t) (ih->ih_vid & 0xff));
224     strlcpy(name->n_voldir1, tmp, sizeof(name->n_voldir1));
225     addtoname(name, name->n_voldir1);
226     (void)int32_to_flipbase64(tmp, (int64_t) ih->ih_vid);
227     strlcpy(name->n_voldir2, tmp, sizeof(name->n_voldir2));
228     addtoname(name, name->n_voldir2);
229 }
230
231 /* namei_HandleToName
232  *
233  * Constructs a file name for the fully qualified handle.
234  * Note that special files end up in /vicepX/InodeDir/Vxx/V*.data/special
235  */
236 void
237 namei_HandleToName(namei_t * name, IHandle_t * ih)
238 {
239     lb64_string_t str;
240     int vno = (int)(ih->ih_ino & NAMEI_VNODEMASK);
241
242     namei_HandleToVolDir(name, ih);
243
244     if (vno == NAMEI_VNODESPECIAL) {
245         strlcpy(name->n_dir1, NAMEI_SPECDIR, sizeof(name->n_dir1));
246         addtoname(name, name->n_dir1);
247         name->n_dir2[0] = '\0';
248     } else {
249         (void)int32_to_flipbase64(str, VNO_DIR1(vno));
250         strlcpy(name->n_dir1, str, sizeof(name->n_dir1));
251         addtoname(name, name->n_dir1);
252         (void)int32_to_flipbase64(str, VNO_DIR2(vno));
253         strlcpy(name->n_dir2, str, sizeof(name->n_dir2));
254         addtoname(name, name->n_dir2);
255     }
256     (void)int64_to_flipbase64(str, (int64_t) ih->ih_ino);
257     strlcpy(name->n_inode, str, sizeof(name->n_inode));
258     addtoname(name, name->n_inode);
259 }
260
261 /* The following is a warning to tell sys-admins to not muck about in this
262  * name space.
263  */
264 #define VICE_README "These files and directories are a part of the AFS \
265 namespace. Modifying them\nin any way will result in loss of AFS data,\n\
266 ownership and permissions included.\n"
267 int
268 namei_ViceREADME(char *partition)
269 {
270     char filename[32];
271     int fd;
272
273     /* Create the inode directory if we're starting for the first time */
274     (void)afs_snprintf(filename, sizeof filename, "%s/%s", partition,
275                        INODEDIR);
276     mkdir(filename, 0700);
277
278     (void)afs_snprintf(filename, sizeof filename, "%s/%s/README", partition,
279                        INODEDIR);
280     fd = afs_open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0444);
281     if (fd >= 0) {
282         (void)write(fd, VICE_README, strlen(VICE_README));
283         close(fd);
284     }
285     return (errno);
286 }
287
288
289 #define create_dir() \
290 do { \
291     if (mkdir(tmp, 0700)<0) { \
292         if (errno != EEXIST) \
293             return -1; \
294     } \
295     else { \
296         *created = 1; \
297     } \
298 } while (0)
299
300 #define create_nextdir(A) \
301 do { \
302          strcat(tmp, "/"); strcat(tmp, A); create_dir();  \
303 } while(0)
304
305 /* namei_CreateDataDirectories
306  *
307  * If creating the file failed because of ENOENT or ENOTDIR, try
308  * creating all the directories first.
309  */
310 static int
311 namei_CreateDataDirectories(namei_t * name, int *created)
312 {
313     char tmp[256];
314
315     *created = 0;
316
317     strlcpy(tmp, name->n_base, sizeof(tmp));
318     create_dir();
319
320     create_nextdir(name->n_voldir1);
321     create_nextdir(name->n_voldir2);
322     create_nextdir(name->n_dir1);
323     if (name->n_dir2[0]) {
324         create_nextdir(name->n_dir2);
325     }
326     return 0;
327 }
328
329 /* delTree(): Deletes an entire tree of directories (no files)
330  * Input:
331  *   root : Full path to the subtree. Should be big enough for PATH_MAX
332  *   tree : the subtree to be deleted is rooted here. Specifies only the
333  *          subtree beginning at tree (not the entire path). It should be
334  *          a pointer into the "root" buffer.
335  * Output:
336  *  errp : errno of the first error encountered during the directory cleanup.
337  *         *errp should have been initialized to 0.
338  *
339  * Return Values:
340  *  -1  : If errors were encountered during cleanup and error is set to
341  *        the first errno.
342  *   0  : Success.
343  *
344  * If there are errors, we try to work around them and delete as many
345  * directories as possible. We don't attempt to remove directories that still
346  * have non-dir entries in them.
347  */
348 static int
349 delTree(char *root, char *tree, int *errp)
350 {
351     char *cp;
352     DIR *ds;
353     struct dirent *dirp;
354     struct afs_stat st;
355
356     if (*tree) {
357         /* delete the children first */
358         cp = strchr(tree, '/');
359         if (cp) {
360             delTree(root, cp + 1, errp);
361             *cp = '\0';
362         } else
363             cp = tree + strlen(tree);   /* move cp to the end of string tree */
364
365         /* now delete all entries in this dir */
366         if ((ds = opendir(root)) != (DIR *) NULL) {
367             errno = 0;
368             while ((dirp = readdir(ds))) {
369                 /* ignore . and .. */
370                 if (!strcmp(dirp->d_name, ".") || !strcmp(dirp->d_name, ".."))
371                     continue;
372                 /* since root is big enough, we reuse the space to
373                  * concatenate the dirname to the current tree
374                  */
375                 strcat(root, "/");
376                 strcat(root, dirp->d_name);
377                 if (afs_stat(root, &st) == 0 && S_ISDIR(st.st_mode)) {
378                     /* delete this subtree */
379                     delTree(root, cp + 1, errp);
380                 } else
381                     *errp = *errp ? *errp : errno;
382
383                 /* recover path to our cur tree by truncating it to
384                  * its original len
385                  */
386                 *cp = 0;
387             }
388             /* if (!errno) -- closedir not implicit if we got an error */
389             closedir(ds);
390         }
391
392         /* finally axe the current dir */
393         if (rmdir(root))
394             *errp = *errp ? *errp : errno;
395
396 #ifndef AFS_PTHREAD_ENV         /* let rx get some work done */
397         IOMGR_Poll();
398 #endif /* !AFS_PTHREAD_ENV */
399
400     }
401
402     /* if valid tree */
403     /* if we encountered errors during cleanup, we return a -1 */
404     if (*errp)
405         return -1;
406
407     return 0;
408
409 }
410
411 /* namei_RemoveDataDirectories
412  * Return Values:
413  * Returns 0 on success.
414  * Returns -1 on error. Typically, callers ignore this error bcause we
415  * can continue running if the removes fail. The salvage process will
416  * finish tidying up for us. We only use the n_base and n_voldir1 entries
417  * and only do rmdir's.
418  */
419
420 static int
421 namei_RemoveDataDirectories(namei_t * name)
422 {
423     char pbuf[MAXPATHLEN], *path = pbuf;
424     int prefixlen = strlen(name->n_base), err = 0;
425     int vollen = strlen(name->n_voldir1);
426     int code;
427
428     strlcpy(path, name->n_path, sizeof(pbuf));
429
430     /* move past the prefix and n_voldir1 */
431     path = path + prefixlen + 1 + vollen + 1;   /* skip over the trailing / */
432
433     /* now delete all dirs upto path */
434     code = delTree(pbuf, path, &err);
435
436     /* We've now deleted everything under /n_base/n_voldir1/n_voldir2 that
437      * we could. Do not delete /n_base/n_voldir1, since doing such might
438      * interrupt another thread trying to create a volume. We could introduce
439      * some locking to make this safe (or only remove it for whole-partition
440      * salvages), but by not deleting it we only leave behind a maximum of
441      * 256 empty directories. So at least for now, don't bother. */
442
443     return code;
444 }
445
446 /* Create the file in the name space.
447  *
448  * Parameters stored as follows:
449  * Regular files:
450  * p1 - volid - implied in containing directory.
451  * p2 - vnode - name is <vno:31-23>/<vno:22-15>/<vno:15-0><uniq:31-5><tag:2-0>
452  * p3 - uniq -- bits 4-0 are in mode bits 4-0
453  * p4 - dv ---- dv:15-0 in uid, dv:29-16 in gid, dv:31-30 in mode:6-5
454  * Special files:
455  * p1 - volid - creation time - dwHighDateTime
456  * p2 - vnode - -1 means special, file goes in "S" subdirectory.
457  * p3 - type -- name is <type>.<tag> where tag is a file name unqiquifier.
458  * p4 - parid - parent volume id - implied in containing directory.
459  *
460  * Return value is the inode number or (Inode)-1 if error.
461  * We "know" there is only one link table, so return EEXIST if there already
462  * is a link table. It's up to the calling code to test errno and increment
463  * the link count.
464  */
465
466 /* namei_MakeSpecIno
467  *
468  * This function is called by VCreateVolume to hide the implementation
469  * details of the inode numbers. This only allows for 7 volume special
470  * types, but if we get that far, this could should be dead by then.
471  */
472 Inode
473 namei_MakeSpecIno(int volid, int type)
474 {
475     Inode ino;
476     ino = NAMEI_INODESPECIAL;
477     type &= NAMEI_TAGMASK;
478     ino |= ((Inode) type) << NAMEI_TAGSHIFT;
479     ino |= ((Inode) volid) << NAMEI_UNIQSHIFT;
480     return ino;
481 }
482
483 /* SetOGM - set owner group and mode bits from parm and tag
484  *
485  * owner - low 15 bits of parm.
486  * group - next 15 bits of parm.
487  * mode - 2 bits of parm, then lowest = 3 bits of tag.
488  */
489 static int
490 SetOGM(int fd, int parm, int tag)
491 {
492     int owner, group, mode;
493
494     owner = parm & 0x7fff;
495     group = (parm >> 15) & 0x7fff;
496     if (fchown(fd, owner, group) < 0)
497         return -1;
498
499     mode = (parm >> 27) & 0x18;
500     mode |= tag & 0x7;
501     if (fchmod(fd, mode) < 0)
502         return -1;
503
504     return 0;
505
506 }
507
508 /* GetOGM - get parm and tag from owner, group and mode bits. */
509 static void
510 GetOGMFromStat(struct afs_stat *status, int *parm, int *tag)
511 {
512     *parm = status->st_uid | (status->st_gid << 15);
513     *parm |= (status->st_mode & 0x18) << 27;
514     *tag = status->st_mode & 0x7;
515 }
516
517 static int
518 GetOGM(int fd, int *parm, int *tag)
519 {
520     struct afs_stat status;
521     if (afs_fstat(fd, &status) < 0)
522         return -1;
523
524     GetOGMFromStat(&status, parm, tag);
525     return 0;
526 }
527
528 int big_vno = 0;                /* Just in case we ever do 64 bit vnodes. */
529
530 /* Derive the name and create it O_EXCL. If that fails we have an error.
531  * Get the tag from a free column in the link table.
532  */
533 Inode
534 namei_icreate(IHandle_t * lh, char *part, int p1, int p2, int p3, int p4)
535 {
536     namei_t name;
537     int fd = -1;
538     int code = 0;
539     int created_dir = 0;
540     IHandle_t tmp;
541     FdHandle_t *fdP;
542     FdHandle_t tfd;
543     int tag;
544     int ogm_parm;
545
546
547     memset((void *)&tmp, 0, sizeof(IHandle_t));
548
549
550     tmp.ih_dev = volutil_GetPartitionID(part);
551     if (tmp.ih_dev == -1) {
552         errno = EINVAL;
553         return -1;
554     }
555
556     if (p2 == -1) {
557         /* Parameters for special file:
558          * p1 - volume id - goes into owner/group/mode
559          * p2 - vnode == -1
560          * p3 - type
561          * p4 - parent volume id
562          */
563         ogm_parm = p1;
564         tag = p3;
565
566         tmp.ih_vid = p4;        /* Use parent volume id, where this file will be. */
567         tmp.ih_ino = namei_MakeSpecIno(p1, p3);
568     } else {
569         int vno = p2 & NAMEI_VNODEMASK;
570         /* Parameters for regular file:
571          * p1 - volume id
572          * p2 - vnode
573          * p3 - uniq
574          * p4 - dv
575          */
576
577         if (vno != p2) {
578             big_vno++;
579             errno = EINVAL;
580             return -1;
581         }
582         /* If GetFreeTag succeeds, it atomically sets link count to 1. */
583         tag = GetFreeTag(lh, p2);
584         if (tag < 0)
585             goto bad;
586
587         /* name is <uniq(p3)><tag><vno(p2)> */
588         tmp.ih_vid = p1;
589         tmp.ih_ino = (Inode) p2;
590         tmp.ih_ino |= ((Inode) tag) << NAMEI_TAGSHIFT;
591         tmp.ih_ino |= ((Inode) p3) << NAMEI_UNIQSHIFT;
592
593         ogm_parm = p4;
594     }
595
596     namei_HandleToName(&name, &tmp);
597     fd = afs_open(name.n_path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0);
598     if (fd < 0) {
599         if (errno == ENOTDIR || errno == ENOENT) {
600             if (namei_CreateDataDirectories(&name, &created_dir) < 0)
601                 goto bad;
602             fd = afs_open(name.n_path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR,
603                           0);
604             if (fd < 0)
605                 goto bad;
606         } else {
607             goto bad;
608         }
609     }
610     if (SetOGM(fd, ogm_parm, tag) < 0) {
611         close(fd);
612         fd = -1;
613         goto bad;
614     }
615
616     if (p2 == -1 && p3 == VI_LINKTABLE) {
617         /* hack at tmp to setup for set link count call. */
618         memset((void *)&tfd, 0, sizeof(FdHandle_t));    /* minimalistic still, but a little cleaner */
619         tfd.fd_ih = &tmp;
620         tfd.fd_fd = fd;
621         code = namei_SetLinkCount(&tfd, (Inode) 0, 1, 0);
622     }
623
624   bad:
625     if (fd >= 0)
626         close(fd);
627
628
629     if (code || (fd < 0)) {
630         if (p2 != -1) {
631             fdP = IH_OPEN(lh);
632             if (fdP) {
633                 namei_SetLinkCount(fdP, tmp.ih_ino, 0, 0);
634                 FDH_CLOSE(fdP);
635             }
636         }
637     }
638     return (code || (fd < 0)) ? (Inode) - 1 : tmp.ih_ino;
639 }
640
641
642 /* namei_iopen */
643 int
644 namei_iopen(IHandle_t * h)
645 {
646     int fd;
647     namei_t name;
648
649     /* Convert handle to file name. */
650     namei_HandleToName(&name, h);
651     fd = afs_open(name.n_path, O_RDWR, 0666);
652     return fd;
653 }
654
655 /* Need to detect vol special file and just unlink. In those cases, the
656  * handle passed in _is_ for the inode. We only check p1 for the special
657  * files.
658  */
659 int
660 namei_dec(IHandle_t * ih, Inode ino, int p1)
661 {
662     int count = 0;
663     namei_t name;
664     int code = 0;
665     FdHandle_t *fdP;
666
667     if ((ino & NAMEI_INODESPECIAL) == NAMEI_INODESPECIAL) {
668         IHandle_t *tmp;
669         int inode_p1, tag;
670         int type = (int)((ino >> NAMEI_TAGSHIFT) & NAMEI_TAGMASK);
671
672         /* Verify this is the right file. */
673         IH_INIT(tmp, ih->ih_dev, ih->ih_vid, ino);
674
675         fdP = IH_OPEN(tmp);
676         if (fdP == NULL) {
677             IH_RELEASE(tmp);
678             errno = EINVAL;
679             return -1;
680         }
681
682         if ((GetOGM(fdP->fd_fd, &inode_p1, &tag) < 0) || (inode_p1 != p1)) {
683             FDH_REALLYCLOSE(fdP);
684             IH_RELEASE(tmp);
685             errno = EINVAL;
686             return -1;
687         }
688
689         /* If it's the link table itself, decrement the link count. */
690         if (type == VI_LINKTABLE) {
691             if ((count = namei_GetLinkCount(fdP, (Inode) 0, 1)) < 0) {
692                 FDH_REALLYCLOSE(fdP);
693                 IH_RELEASE(tmp);
694                 return -1;
695             }
696
697             count--;
698             if (namei_SetLinkCount(fdP, (Inode) 0, count < 0 ? 0 : count, 1) <
699                 0) {
700                 FDH_REALLYCLOSE(fdP);
701                 IH_RELEASE(tmp);
702                 return -1;
703             }
704
705             if (count > 0) {
706                 FDH_REALLYCLOSE(fdP);
707                 IH_RELEASE(tmp);
708                 return 0;
709             }
710         }
711
712         namei_HandleToName(&name, tmp);
713         if ((code = unlink(name.n_path)) == 0) {
714             if (type == VI_LINKTABLE) {
715                 /* Try to remove directory. If it fails, that's ok.
716                  * Salvage will clean up.
717                  */
718                 (void)namei_RemoveDataDirectories(&name);
719             }
720         }
721         FDH_REALLYCLOSE(fdP);
722         IH_RELEASE(tmp);
723     } else {
724         /* Get a file descriptor handle for this Inode */
725         fdP = IH_OPEN(ih);
726         if (fdP == NULL) {
727             return -1;
728         }
729
730         if ((count = namei_GetLinkCount(fdP, ino, 1)) < 0) {
731             FDH_REALLYCLOSE(fdP);
732             return -1;
733         }
734
735         count--;
736         if (count >= 0) {
737             if (namei_SetLinkCount(fdP, ino, count, 1) < 0) {
738                 FDH_REALLYCLOSE(fdP);
739                 return -1;
740             }
741         } else {
742             IHandle_t *th;
743             IH_INIT(th, ih->ih_dev, ih->ih_vid, ino);
744             Log("Warning: Lost ref on ihandle dev %d vid %d ino %" AFS_INT64_FMT "\n",
745                 th->ih_dev, th->ih_vid, (afs_int64)th->ih_ino);
746             IH_RELEASE(th);
747
748             /* If we're less than 0, someone presumably unlinked;
749                don't bother setting count to 0, but we need to drop a lock */
750             if (namei_SetLinkCount(fdP, ino, 0, 1) < 0) {
751                 FDH_REALLYCLOSE(fdP);
752                 return -1;
753             }
754         }
755         if (count == 0) {
756             IHandle_t *th;
757             IH_INIT(th, ih->ih_dev, ih->ih_vid, ino);
758
759             namei_HandleToName(&name, th);
760             IH_RELEASE(th);
761             code = unlink(name.n_path);
762         }
763         FDH_CLOSE(fdP);
764     }
765
766     return code;
767 }
768
769 int
770 namei_inc(IHandle_t * h, Inode ino, int p1)
771 {
772     int count;
773     int code = 0;
774     FdHandle_t *fdP;
775
776     if ((ino & NAMEI_INODESPECIAL) == NAMEI_INODESPECIAL) {
777         int type = (int)((ino >> NAMEI_TAGSHIFT) & NAMEI_TAGMASK);
778         if (type != VI_LINKTABLE)
779             return 0;
780         ino = (Inode) 0;
781     }
782
783     /* Get a file descriptor handle for this Inode */
784     fdP = IH_OPEN(h);
785     if (fdP == NULL) {
786         return -1;
787     }
788
789     if ((count = namei_GetLinkCount(fdP, ino, 1)) < 0)
790         code = -1;
791     else {
792         count++;
793         if (count > 7) {
794             errno = EINVAL;
795             code = -1;
796             count = 7;
797         }
798         if (namei_SetLinkCount(fdP, ino, count, 1) < 0)
799             code = -1;
800     }
801     if (code) {
802         FDH_REALLYCLOSE(fdP);
803     } else {
804         FDH_CLOSE(fdP);
805     }
806     return code;
807 }
808
809 int
810 namei_replace_file_by_hardlink(IHandle_t *hLink, IHandle_t *hTarget)
811 {
812     afs_int32 code;
813     namei_t nameLink;
814     namei_t nameTarget;
815
816     /* Convert handle to file name. */
817     namei_HandleToName(&nameLink, hLink);
818     namei_HandleToName(&nameTarget, hTarget);
819
820     unlink(nameLink.n_path);
821     code = link(nameTarget.n_path, nameLink.n_path);
822     return code;
823 }
824
825 int
826 namei_copy_on_write(IHandle_t *h)
827 {
828     afs_int32 fd, code = 0;
829     namei_t name;
830     FdHandle_t *fdP;
831     struct afs_stat tstat;
832     afs_foff_t offset;
833
834     namei_HandleToName(&name, h);
835     if (afs_stat(name.n_path, &tstat) < 0)
836         return EIO;
837     if (tstat.st_nlink > 1) {                   /* do a copy on write */
838         char path[259];
839         char *buf;
840         afs_size_t size;
841         ssize_t tlen;
842
843         fdP = IH_OPEN(h);
844         if (!fdP)
845             return EIO;
846         afs_snprintf(path, sizeof(path), "%s-tmp", name.n_path);
847         fd = afs_open(path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0);
848         if (fd < 0) {
849             FDH_CLOSE(fdP);
850             return EIO;
851         }
852         buf = malloc(8192);
853         if (!buf) {
854             close(fd);
855             unlink(path);
856             FDH_CLOSE(fdP);
857             return ENOMEM;
858         }
859         size = tstat.st_size;
860         offset = 0;
861         while (size) {
862             tlen = size > 8192 ? 8192 : size;
863             if (FDH_PREAD(fdP, buf, tlen, offset) != tlen)
864                 break;
865             if (write(fd, buf, tlen) != tlen)
866                 break;
867             size -= tlen;
868             offset += tlen;
869         }
870         close(fd);
871         FDH_REALLYCLOSE(fdP);
872         free(buf);
873         if (size)
874             code = EIO;
875         else {
876             unlink(name.n_path);
877             code = rename(path, name.n_path);
878         }
879     }
880     return code;
881 }
882
883 /************************************************************************
884  * File Name Structure
885  ************************************************************************
886  *
887  * Each AFS file needs a unique name and it needs to be findable with
888  * minimal lookup time. Note that the constraint on the number of files and
889  * directories in a volume is the size of the vnode index files and the
890  * max file size AFS supports (for internal files) of 2^31. Since a record
891  * in the small vnode index file is 64 bytes long, we can have at most
892  * (2^31)/64 or 33554432 files. A record in the large index file is
893  * 256 bytes long, giving a maximum of (2^31)/256 = 8388608 directories.
894  * Another layout parameter is that there is roughly a 16 to 1 ratio between
895  * the number of files and the number of directories.
896  *
897  * Using this information we can see that a layout of 256 directories, each
898  * with 512 subdirectories and each of those having 512 files gives us
899  * 256*512*512 = 67108864 AFS files and directories.
900  *
901  * The volume, vnode, uniquifier and data version, as well as the tag
902  * are required, either for finding the file or for salvaging. It's best to
903  * restrict the name to something that can be mapped into 64 bits so the
904  * "Inode" is easily comparable (using "==") to other "Inodes". The tag
905  * is used to distinguish between different versions of the same file
906  * which are currently in the RW and clones of a volume. See "Link Table
907  * Organization" below for more information on the tag. The tag is
908  * required in the name of the file to ensure a unique name.
909  *
910  * We can store data in the uid, gid and mode bits of the files, provided
911  * the directories have root only access. This gives us 15 bits for each
912  * of uid and gid (GNU chown considers 65535 to mean "don't change").
913  * There are 9 available mode bits. Adn we need to store a total of
914  * 32 (volume id) + 26 (vnode) + 32 (uniquifier) + 32 (data-version) + 3 (tag)
915  * or 131 bits somewhere.
916  *
917  * The format of a file name for a regular file is:
918  * /vicepX/AFSIDat/V1/V2/AA/BB/<tag><uniq><vno>
919  * V1 - low 8 bits of RW volume id
920  * V2 - all bits of RW volume id
921  * AA - high 8 bits of vnode number.
922  * BB - next 9 bits of vnode number.
923  * <tag><uniq><vno> - file name
924  *
925  * Volume special files are stored in a separate directory:
926  * /vicepX/AFSIDat/V1/V2/special/<tag><uniq><vno>
927  *
928  *
929  * The vnode is hashed into the directory using the high bits of the
930  * vnode number. This is so that consecutively created vnodes are in
931  * roughly the same area on the disk. This will at least be optimal if
932  * the user is creating many files in the same AFS directory. The name
933  * should be formed so that the leading characters are different as quickly
934  * as possible, leading to faster discards of incorrect matches in the
935  * lookup code.
936  *
937  */
938
939
940 /************************************************************************
941  *  Link Table Organization
942  ************************************************************************
943  *
944  * The link table volume special file is used to hold the link counts that
945  * are held in the inodes in inode based AFS vice filesystems. For user
946  * space access, the link counts are being kept in a separate
947  * volume special file. The file begins with the usual version stamp
948  * information and is then followed by one row per vnode number. vnode 0
949  * is used to hold the link count of the link table itself. That is because
950  * the same link table is shared among all the volumes of the volume group
951  * and is deleted only when the last volume of a volume group is deleted.
952  *
953  * Within each row, the columns are 3 bits wide. They can each hold a 0 based
954  * link count from 0 through 7. Each colume represents a unique instance of
955  * that vnode. Say we have a file shared between the RW and a RO and a
956  * different version of the file (or a different uniquifer) for the BU volume.
957  * Then one column would be holding the link count of 2 for the RW and RO
958  * and a different column would hold the link count of 1 for the BU volume.
959  * Note that we allow only 5 volumes per file, giving 15 bits used in the
960  * short.
961  */
962 #define LINKTABLE_WIDTH 2
963 #define LINKTABLE_SHIFT 1       /* log 2 = 1 */
964
965 /**
966  * compute namei link table file and bit offset from inode number.
967  *
968  * @param[in]   ino     inode number
969  * @param[out]  offset  link table file offset
970  * @param[out]  index   bit offset within 2-byte record
971  *
972  * @internal
973  */
974 static void
975 namei_GetLCOffsetAndIndexFromIno(Inode ino, afs_foff_t * offset, int *index)
976 {
977     int toff = (int)(ino & NAMEI_VNODEMASK);
978     int tindex = (int)((ino >> NAMEI_TAGSHIFT) & NAMEI_TAGMASK);
979
980     *offset = (afs_foff_t) ((toff << LINKTABLE_SHIFT) + 8);     /* * 2 + sizeof stamp */
981     *index = (tindex << 1) + tindex;
982 }
983
984 #ifdef AFS_PTHREAD_ENV
985 /* XXX do static initializers work for WINNT/pthread? */
986 pthread_mutex_t _namei_glc_lock = PTHREAD_MUTEX_INITIALIZER;
987 #define NAMEI_GLC_LOCK MUTEX_ENTER(&_namei_glc_lock)
988 #define NAMEI_GLC_UNLOCK MUTEX_EXIT(&_namei_glc_lock)
989 #else /* !AFS_PTHREAD_ENV */
990 #define NAMEI_GLC_LOCK
991 #define NAMEI_GLC_UNLOCK
992 #endif /* !AFS_PTHREAD_ENV */
993
994 /**
995  * get the link count of an inode.
996  *
997  * @param[in]  h        namei link count table file handle
998  * @param[in]  ino      inode number for which we are requesting a link count
999  * @param[in]  lockit   if asserted, return with lock held on link table file
1000  * @param[in]  fixup    if asserted, write 1 to link count when read() returns
1001  *                      zero (at EOF)
1002  * @param[in]  nowrite  return success on zero byte read or ZLC
1003  *
1004  * @post if lockit asserted and lookup was successful, will return with write
1005  *       lock on link table file descriptor
1006  *
1007  * @return link count
1008  *    @retval -1 namei link table i/o error
1009  *
1010  * @internal
1011  */
1012 static int
1013 namei_GetLinkCount2(FdHandle_t * h, Inode ino, int lockit, int fixup, int nowrite)
1014 {
1015     unsigned short row = 0;
1016     afs_foff_t offset;
1017     ssize_t rc;
1018     int index;
1019
1020     /* there's no linktable yet. the salvager will create one later */
1021     if (h->fd_fd == -1 && fixup)
1022        return 1;
1023     namei_GetLCOffsetAndIndexFromIno(ino, &offset, &index);
1024
1025     if (lockit) {
1026         if (flock(h->fd_fd, LOCK_EX) < 0)
1027             return -1;
1028     }
1029
1030     rc = FDH_PREAD(h, (char*)&row, sizeof(row), offset);
1031     if ((rc == 0 || !((row >> index) & NAMEI_TAGMASK)) && fixup && nowrite)
1032         return 1;
1033     if (rc == 0 && fixup) {
1034         /*
1035          * extend link table and write a link count of 1 for ino
1036          *
1037          * in order to make MT-safe, truncation (extension really)
1038          * must happen under a mutex
1039          */
1040         struct stat st;
1041         NAMEI_GLC_LOCK;
1042         if (fstat(h->fd_fd, &st) || st.st_size >= offset+sizeof(row)) {
1043             NAMEI_GLC_UNLOCK;
1044             goto bad_getLinkByte;
1045         }
1046         FDH_TRUNC(h, offset+sizeof(row));
1047         row = 1 << index;
1048         rc = FDH_PWRITE(h, (char *)&row, sizeof(row), offset);
1049         NAMEI_GLC_UNLOCK;
1050     }
1051     if (rc != sizeof(row)) {
1052         goto bad_getLinkByte;
1053     }
1054
1055     if (fixup && !((row >> index) & NAMEI_TAGMASK)) {
1056         /*
1057          * fix up zlc
1058          *
1059          * in order to make this mt-safe, we need to do the read-modify-write
1060          * under a mutex.  thus, we repeat the read inside the lock.
1061          */
1062         NAMEI_GLC_LOCK;
1063         rc = FDH_PREAD(h, (char *)&row, sizeof(row), offset);
1064         if (rc == sizeof(row)) {
1065             row |= 1<<index;
1066             rc = FDH_PWRITE(h, (char *)&row, sizeof(row), offset);
1067         }
1068         NAMEI_GLC_UNLOCK;
1069         if (rc != sizeof(row))
1070             goto bad_getLinkByte;
1071     }
1072
1073     return (int)((row >> index) & NAMEI_TAGMASK);
1074
1075   bad_getLinkByte:
1076     if (lockit)
1077         flock(h->fd_fd, LOCK_UN);
1078     return -1;
1079 }
1080
1081 int
1082 namei_GetLinkCount(FdHandle_t * h, Inode ino, int lockit)
1083 {
1084     return namei_GetLinkCount2(h, ino, lockit, 0, 1);
1085 }
1086
1087 /* Return a free column index for this vnode. */
1088 static int
1089 GetFreeTag(IHandle_t * ih, int vno)
1090 {
1091     FdHandle_t *fdP;
1092     afs_foff_t offset;
1093     int col;
1094     int coldata;
1095     short row;
1096     ssize_t nBytes;
1097
1098
1099     fdP = IH_OPEN(ih);
1100     if (fdP == NULL)
1101         return -1;
1102
1103     /* Only one manipulates at a time. */
1104     if (flock(fdP->fd_fd, LOCK_EX) < 0) {
1105         FDH_REALLYCLOSE(fdP);
1106         return -1;
1107     }
1108
1109     offset = (vno << LINKTABLE_SHIFT) + 8;      /* * 2 + sizeof stamp */
1110
1111     nBytes = FDH_PREAD(fdP, (char *)&row, sizeof(row), offset);
1112     if (nBytes != sizeof(row)) {
1113         if (nBytes != 0)
1114             goto badGetFreeTag;
1115         row = 0;
1116     }
1117
1118     /* Now find a free column in this row and claim it. */
1119     for (col = 0; col < NAMEI_MAXVOLS; col++) {
1120         coldata = 7 << (col * 3);
1121         if ((row & coldata) == 0)
1122             break;
1123     }
1124     if (col >= NAMEI_MAXVOLS) {
1125         errno = ENOSPC;
1126         goto badGetFreeTag;
1127     }
1128
1129     coldata = 1 << (col * 3);
1130     row |= coldata;
1131
1132     if (FDH_PWRITE(fdP, (char *)&row, sizeof(row), offset) != sizeof(row)) {
1133         goto badGetFreeTag;
1134     }
1135     FDH_SYNC(fdP);
1136     flock(fdP->fd_fd, LOCK_UN);
1137     FDH_REALLYCLOSE(fdP);
1138     return col;;
1139
1140   badGetFreeTag:
1141     flock(fdP->fd_fd, LOCK_UN);
1142     FDH_REALLYCLOSE(fdP);
1143     return -1;
1144 }
1145
1146
1147
1148 /* namei_SetLinkCount
1149  * If locked is set, assume file is locked. Otherwise, lock file before
1150  * proceeding to modify it.
1151  */
1152 int
1153 namei_SetLinkCount(FdHandle_t * fdP, Inode ino, int count, int locked)
1154 {
1155     afs_foff_t offset;
1156     int index;
1157     unsigned short row;
1158     int junk;
1159     ssize_t nBytes = -1;
1160
1161     namei_GetLCOffsetAndIndexFromIno(ino, &offset, &index);
1162
1163     if (!locked) {
1164         if (flock(fdP->fd_fd, LOCK_EX) < 0) {
1165             return -1;
1166         }
1167     }
1168
1169     nBytes = FDH_PREAD(fdP, (char *)&row, sizeof(row), offset);
1170     if (nBytes != sizeof(row)) {
1171         if (nBytes != 0) {
1172             errno = EBADF;
1173             goto bad_SetLinkCount;
1174         }
1175         row = 0;
1176     }
1177
1178     junk = 7 << index;
1179     count <<= index;
1180     row &= (unsigned short)~junk;
1181     row |= (unsigned short)count;
1182
1183     if (FDH_PWRITE(fdP, (char *)&row, sizeof(short), offset) != sizeof(short)) {
1184         errno = EBADF;
1185         goto bad_SetLinkCount;
1186     }
1187     FDH_SYNC(fdP);
1188
1189     nBytes = 0;
1190
1191
1192   bad_SetLinkCount:
1193     flock(fdP->fd_fd, LOCK_UN);
1194
1195     return nBytes;
1196 }
1197
1198
1199 /* ListViceInodes - write inode data to a results file. */
1200 static int DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
1201                        unsigned int volid);
1202 static int DecodeVolumeName(char *name, unsigned int *vid);
1203 static int namei_ListAFSSubDirs(IHandle_t * dirIH,
1204                                 int (*write_fun) (FILE *,
1205                                                   struct ViceInodeInfo *,
1206                                                   char *, char *), FILE * fp,
1207                                 int (*judgeFun) (struct ViceInodeInfo *,
1208                                                  afs_uint32 vid, void *),
1209                                 afs_uint32 singleVolumeNumber, void *rock);
1210
1211
1212 /* WriteInodeInfo
1213  *
1214  * Write the inode data to the results file.
1215  *
1216  * Returns -2 on error, 0 on success.
1217  *
1218  * This is written as a callback simply so that other listing routines
1219  * can use the same inode reading code.
1220  */
1221 static int
1222 WriteInodeInfo(FILE * fp, struct ViceInodeInfo *info, char *dir, char *name)
1223 {
1224     int n;
1225     n = fwrite(info, sizeof(*info), 1, fp);
1226     return (n == 1) ? 0 : -2;
1227 }
1228
1229
1230 int mode_errors;                /* Number of errors found in mode bits on directories. */
1231 void
1232 VerifyDirPerms(char *path)
1233 {
1234     struct afs_stat status;
1235
1236     if (afs_stat(path, &status) < 0) {
1237         Log("Unable to stat %s. Please manually verify mode bits for this"
1238             " directory\n", path);
1239     } else {
1240         if (((status.st_mode & 0777) != 0700) || (status.st_uid != 0))
1241             mode_errors++;
1242     }
1243 }
1244
1245 /**
1246  * Fill the results file with the requested inode information.
1247  *
1248  * This code optimizes single volume salvages by just looking at that one
1249  * volume's directory.
1250  *
1251  * @param[in]   devname             device name string
1252  * @param[in]   moutnedOn           vice partition mount point
1253  * @param[in]   resultFile          result file in which to write inode
1254  *                                  metadata.  If NULL, write routine is not
1255  *                                  called.
1256  * @param[in]   judgeInode          filter function pointer.  if not NULL, only
1257  *                                  inodes for which this routine returns non-
1258  *                                  zero will be written to the results file.
1259  * @param[in]   singleVolumeNumber  volume id filter
1260  * @param[out]  forcep              always set to 0 for namei impl
1261  * @param[in]   forceR              not used by namei impl
1262  * @param[in]   wpath               not used by namei impl
1263  * @param[in]   rock                opaque pointer passed to judgeInode
1264  *
1265  * @return operation status
1266  *    @retval 0   success
1267  *    @retval -1  complete failure, salvage should terminate.
1268  *    @retval -2  not enough space on partition, salvager has error message
1269  *                for this.
1270  */
1271 int
1272 ListViceInodes(char *devname, char *mountedOn, FILE *inodeFile,
1273                int (*judgeInode) (struct ViceInodeInfo * info, afs_uint32 vid, void *rock),
1274                afs_uint32 singleVolumeNumber, int *forcep, int forceR, char *wpath,
1275                void *rock)
1276 {
1277     int ninodes;
1278     struct afs_stat status;
1279
1280     *forcep = 0; /* no need to salvage until further notice */
1281
1282     /* Verify protections on directories. */
1283     mode_errors = 0;
1284     VerifyDirPerms(mountedOn);
1285
1286     ninodes =
1287         namei_ListAFSFiles(mountedOn, WriteInodeInfo, inodeFile, judgeInode,
1288                            singleVolumeNumber, rock);
1289
1290     if (!inodeFile)
1291         return ninodes;
1292
1293     if (ninodes < 0) {
1294         return ninodes;
1295     }
1296
1297     if (fflush(inodeFile) == EOF) {
1298         Log("Unable to successfully flush inode file for %s\n", mountedOn);
1299         return -2;
1300     }
1301     if (fsync(fileno(inodeFile)) == -1) {
1302         Log("Unable to successfully fsync inode file for %s\n", mountedOn);
1303         return -2;
1304     }
1305
1306     /*
1307      * Paranoia:  check that the file is really the right size
1308      */
1309     if (afs_fstat(fileno(inodeFile), &status) == -1) {
1310         Log("Unable to successfully stat inode file for %s\n", mountedOn);
1311         return -2;
1312     }
1313     if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
1314         Log("Wrong size (%d instead of %lu) in inode file for %s\n",
1315             (int) status.st_size,
1316             (long unsigned int) ninodes * sizeof(struct ViceInodeInfo),
1317             mountedOn);
1318         return -2;
1319     }
1320     return 0;
1321 }
1322
1323
1324 /**
1325  * Collect all the matching AFS files on the drive.
1326  * If singleVolumeNumber is non-zero, just return files for that volume.
1327  *
1328  * @param[in] dev                 vice partition path
1329  * @param[in] writeFun            function pointer to a function which
1330  *                                writes inode information to FILE fp
1331  * @param[in] fp                  file stream where inode metadata is sent
1332  * @param[in] judgeFun            filter function pointer.  if not NULL,
1333  *                                only entries for which a non-zero value
1334  *                                is returned are written to fp
1335  * @param[in] singleVolumeNumber  volume id filter.  if nonzero, only
1336  *                                process files for that specific volume id
1337  * @param[in] rock                opaque pointer passed into writeFun and
1338  *                                judgeFun
1339  *
1340  * @return operation status
1341  *    @retval <0 error
1342  *    @retval >=0 number of matching files found
1343  */
1344 int
1345 namei_ListAFSFiles(char *dev,
1346                    int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
1347                                     char *),
1348                    FILE * fp,
1349                    int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *),
1350                    afs_uint32 singleVolumeNumber, void *rock)
1351 {
1352     IHandle_t ih;
1353     namei_t name;
1354     int ninodes = 0;
1355     DIR *dirp1, *dirp2;
1356     struct dirent *dp1, *dp2;
1357     char path2[512];
1358 #ifdef DELETE_ZLC
1359     static void FreeZLCList(void);
1360 #endif
1361
1362     memset((void *)&ih, 0, sizeof(IHandle_t));
1363     ih.ih_dev = volutil_GetPartitionID(dev);
1364
1365     if (singleVolumeNumber) {
1366         ih.ih_vid = singleVolumeNumber;
1367         namei_HandleToVolDir(&name, &ih);
1368         ninodes =
1369             namei_ListAFSSubDirs(&ih, writeFun, fp, judgeFun,
1370                                  singleVolumeNumber, rock);
1371         if (ninodes < 0)
1372             return ninodes;
1373     } else {
1374         /* Find all volume data directories and descend through them. */
1375         namei_HandleToInodeDir(&name, &ih);
1376         ninodes = 0;
1377         dirp1 = opendir(name.n_path);
1378         if (!dirp1)
1379             return 0;
1380         while ((dp1 = readdir(dirp1))) {
1381             if (*dp1->d_name == '.')
1382                 continue;
1383             afs_snprintf(path2, sizeof(path2), "%s/%s", name.n_path,
1384                          dp1->d_name);
1385             dirp2 = opendir(path2);
1386             if (dirp2) {
1387                 while ((dp2 = readdir(dirp2))) {
1388                     if (*dp2->d_name == '.')
1389                         continue;
1390                     if (!DecodeVolumeName(dp2->d_name, &ih.ih_vid)) {
1391                         ninodes +=
1392                             namei_ListAFSSubDirs(&ih, writeFun, fp, judgeFun,
1393                                                  0, rock);
1394                     }
1395                 }
1396                 closedir(dirp2);
1397             }
1398         }
1399         closedir(dirp1);
1400     }
1401 #ifdef DELETE_ZLC
1402     FreeZLCList();
1403 #endif
1404     return ninodes;
1405 }
1406
1407 #ifdef DELETE_ZLC
1408 static void AddToZLCDeleteList(char dir, char *name);
1409 static void DeleteZLCFiles(char *path);
1410 #endif
1411
1412 /**
1413  * examine a namei volume special file.
1414  *
1415  * @param[in] path1               volume special directory path
1416  * @param[in] dname               directory entry name
1417  * @param[in] myIH                inode handle to volume directory
1418  * @param[out] linkHandle         namei link count fd handle.  if
1419  *                                the inode in question is the link
1420  *                                table, then the FdHandle is populated
1421  * @param[in] writeFun            metadata write function pointer
1422  * @param[in] fp                  file pointer where inode metadata
1423  *                                is written by (*writeFun)()
1424  * @param[in] judgeFun            inode filter function pointer.  if
1425  *                                not NULL, only inodes for which this
1426  *                                function returns non-zero are recorded
1427  *                                into fp by writeFun
1428  * @param[in] singleVolumeNumer   volume id filter.  if non-zero, only
1429  *                                inodes associated with this volume id
1430  *                                are recorded by writeFun
1431  * @param[in] rock                opaque pointer passed to writeFun and
1432  *                                judgeFun
1433  *
1434  * @return operation status
1435  *    @retval 1 count this inode
1436  *    @retval 0 don't count this inode
1437  *    @retval -1 failure
1438  *
1439  * @internal
1440  */
1441 static int
1442 _namei_examine_special(char * path1,
1443                        char * dname,
1444                        IHandle_t * myIH,
1445                        FdHandle_t * linkHandle,
1446                        int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
1447                                         char *),
1448                        FILE * fp,
1449                        int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *),
1450                        int singleVolumeNumber,
1451                        void *rock)
1452 {
1453     int ret = 0;
1454     struct ViceInodeInfo info;
1455
1456     if (DecodeInode(path1, dname, &info, myIH->ih_vid) < 0) {
1457         ret = 0;
1458         goto error;
1459     }
1460
1461     if (info.u.param[2] != VI_LINKTABLE) {
1462         info.linkCount = 1;
1463     } else {
1464         char path2[512];
1465         /* Open this handle */
1466         (void)afs_snprintf(path2, sizeof(path2),
1467                            "%s/%s", path1, dname);
1468         linkHandle->fd_fd = afs_open(path2, Testing ? O_RDONLY : O_RDWR, 0666);
1469         info.linkCount =
1470             namei_GetLinkCount2(linkHandle, (Inode) 0, 1, 1, Testing);
1471     }
1472
1473     if (!judgeFun ||
1474         (*judgeFun) (&info, singleVolumeNumber, rock)) {
1475         ret = 1;
1476         if ((*writeFun) (fp, &info, path1, dname) < 0) {
1477             ret = -1;
1478         }
1479     }
1480
1481  error:
1482     return ret;
1483 }
1484
1485 /**
1486  * examine a namei file.
1487  *
1488  * @param[in] path1               volume special directory path
1489  * @param[in] dname               directory entry name
1490  * @param[in] myIH                inode handle to volume directory
1491  * @param[in] linkHandle          namei link count fd handle.
1492  * @param[in] writeFun            metadata write function pointer
1493  * @param[in] fp                  file pointer where inode metadata
1494  *                                is written by (*writeFun)()
1495  * @param[in] judgeFun            inode filter function pointer.  if
1496  *                                not NULL, only inodes for which this
1497  *                                function returns non-zero are recorded
1498  *                                into fp by writeFun
1499  * @param[in] singleVolumeNumer   volume id filter.  if non-zero, only
1500  *                                inodes associated with this volume id
1501  *                                are recorded by writeFun
1502  * @param[in] rock                opaque pointer passed to writeFun and
1503  *                                judgeFun
1504  *
1505  * @return operation status
1506  *    @retval 1 count this inode
1507  *    @retval 0 don't count this inode
1508  *    @retval -1 failure
1509  *    @retval -2 request ZLC delete
1510  *
1511  * @internal
1512  */
1513 static int
1514 _namei_examine_reg(char * path3,
1515                    char * dname,
1516                    IHandle_t * myIH,
1517                    FdHandle_t * linkHandle,
1518                    int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
1519                                     char *),
1520                    FILE * fp,
1521                    int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *),
1522                    int singleVolumeNumber,
1523                    void *rock)
1524 {
1525     int ret = 0;
1526     struct ViceInodeInfo info;
1527 #ifdef DELETE_ZLC
1528     int i; /* XXX this isn't set anywhere, nor was it set in
1529             *     namei_ListAFSSubdirs.  wtf? */
1530 #endif
1531
1532     if (DecodeInode(path3, dname, &info, myIH->ih_vid) < 0) {
1533         goto error;
1534     }
1535
1536     info.linkCount =
1537         namei_GetLinkCount2(linkHandle,
1538                             info.inodeNumber, 1, 1, Testing);
1539     if (info.linkCount == 0) {
1540 #ifdef DELETE_ZLC
1541         Log("Found 0 link count file %s/%s, deleting it.\n", path3, dname);
1542 #ifdef AFS_SALSRV_ENV
1543         /* defer -- the AddToZLCDeleteList() interface is not MT-safe */
1544         ret = -2;
1545 #else /* !AFS_SALSRV_ENV */
1546         AddToZLCDeleteList((char)i, dname);
1547 #endif /* !AFS_SALSRV_ENV */
1548 #else /* !DELETE_ZLC */
1549         Log("Found 0 link count file %s/%s.\n", path3,
1550             dname);
1551 #endif
1552         goto error;
1553     }
1554
1555     if (!judgeFun ||
1556         (*judgeFun) (&info, singleVolumeNumber, rock)) {
1557         ret = 1;
1558         if ((*writeFun) (fp, &info, path3, dname) < 0) {
1559             ret = -1;
1560         }
1561     }
1562
1563  error:
1564     return ret;
1565 }
1566
1567 /**
1568  * listsubdirs work queue node.
1569  */
1570 struct listsubdirs_work_node {
1571 #ifdef AFS_SALSRV_ENV
1572     int *error;                         /**< *error set if an error was
1573                                          *   encountered in any listsubdirs
1574                                          *   thread. */
1575 #endif
1576
1577     IHandle_t * IH;                     /**< volume directory handle */
1578     FdHandle_t *linkHandle;             /**< namei link count fd handle. when
1579                                          *   examinining the link table special
1580                                          *   inode, this will be pointed at the
1581                                          *   link table
1582                                          */
1583     FILE * fp;                          /**< file pointer for writeFun */
1584
1585     /** function which will write inode metadata to fp */
1586     int (*writeFun) (FILE *, struct ViceInodeInfo *, char *, char *);
1587
1588     /** inode filter function */
1589     int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *);
1590     int singleVolumeNumber;             /**< volume id filter */
1591     void * rock;                        /**< pointer passed to writeFun and judgeFun */
1592     int code;                           /**< return code from examine function */
1593     int special;                        /**< asserted when this is a volume
1594                                          *   special file */
1595 };
1596
1597 /**
1598  * simple wrapper around _namei_examine_special and _namei_examine_reg.
1599  *
1600  * @param[in] work  the struct listsubdirs_work_node for the associated
1601  *                  "list subdirs" job
1602  * @param[in] dir   the directory to examine
1603  * @param[in] filename  the filename in 'dir' to examine
1604  *
1605  * @return operation status
1606  *   @retval 1  count this inode
1607  *   @retval 0  don't count this inode
1608  *   @retval -1 failure
1609  */
1610 static_inline int
1611 _namei_examine_file(const struct listsubdirs_work_node *work, char *dir,
1612                     char *filename)
1613 {
1614     if (work->special) {
1615         return _namei_examine_special(dir, filename, work->IH,
1616                                       work->linkHandle, work->writeFun, work->fp,
1617                                       work->judgeFun, work->singleVolumeNumber,
1618                                       work->rock);
1619     } else {
1620         return _namei_examine_reg(dir, filename, work->IH,
1621                                   work->linkHandle, work->writeFun, work->fp,
1622                                   work->judgeFun, work->singleVolumeNumber,
1623                                   work->rock);
1624     }
1625 }
1626
1627
1628 #ifdef AFS_SALSRV_ENV
1629 /** @addtogroup afs_vol_salsrv_pario */
1630 /*@{*/
1631
1632 /**
1633  * arguments for the _namei_examine_file_cbk callback function.
1634  */
1635 struct listsubdirs_args {
1636     const struct listsubdirs_work_node *work; /**< arguments that are the same
1637                                                *   for all invocations of
1638                                                *   _namei_examine_file_cbk, in
1639                                                *   threads */
1640     int *result;        /**< where we can store the return code of _namei_examine_file */
1641
1642     char dir[512];      /**< directory to examine */
1643     char filename[256]; /**< filename in 'dir' to examine */
1644 };
1645
1646 /**
1647  * a node in the list of results of listsubdir jobs.
1648  */
1649 struct listsubdirs_result {
1650     struct rx_queue q;
1651     int inodes;        /**< return value from _namei_examine_file */
1652 };
1653
1654 /**
1655  * clean up a list of 'struct listsubdirs_result's and interpret the results.
1656  *
1657  * @param[in] resultlist  a list of 'struct listsubdirs_result's
1658  *
1659  * @return number of inodes found
1660  *   @retval -1  error
1661  */
1662 static int
1663 _namei_listsubdirs_cleanup_results(struct rx_queue *resultlist)
1664 {
1665     struct listsubdirs_result *res, *nres;
1666     int ret = 0;
1667
1668     for(queue_Scan(resultlist, res, nres, listsubdirs_result)) {
1669         if (ret < 0) {
1670             /* noop, retain erroneous error code */
1671         } else if (res->inodes < 0) {
1672             ret = -1;
1673         } else {
1674             ret += res->inodes;
1675         }
1676
1677         queue_Remove(res);
1678         free(res);
1679         res = NULL;
1680     }
1681
1682     return ret;
1683 }
1684
1685 /**
1686  * wait for the spawned listsubdirs jobs to finish, and return how many inodes
1687  * they found.
1688  *
1689  * @param[in] queue    queue to wait to finish
1690  * @param[in] resultlist list of 'struct listsubdirs_result's that the queued
1691  *                       jobs are storing their results in
1692  *
1693  * @return number of inodes found
1694  *   @retval -1  error
1695  */
1696 static int
1697 _namei_listsubdirs_wait(struct afs_work_queue *queue, struct rx_queue *resultlist)
1698 {
1699     int code;
1700
1701     code = afs_wq_wait_all(queue);
1702     if (code) {
1703         return -1;
1704     }
1705
1706     return _namei_listsubdirs_cleanup_results(resultlist);
1707 }
1708
1709 /**
1710  * work queue entry point for examining namei files.
1711  *
1712  * @param[in] queue        pointer to struct Vwork_queue
1713  * @param[in] node         pointer to struct Vwork_queue_node
1714  * @param[in] queue_rock   opaque pointer to struct salsrv_pool_state
1715  * @param[in] node_rock    opaque pointer to struct listsubdirs_work_node
1716  * @param[in] caller_rock  opaque pointer to struct salsrv_worker_thread_state
1717  *
1718  * @return operation status
1719  *
1720  * @see Vwork_queue_callback_func_t
1721  *
1722  * @internal
1723  */
1724 static int
1725 _namei_examine_file_cbk(struct afs_work_queue *queue,
1726                         struct afs_work_queue_node *node,
1727                         void *queue_rock,
1728                         void *node_rock,
1729                         void *caller_rock)
1730 {
1731     int code;
1732     struct listsubdirs_args *args = node_rock;
1733     const struct listsubdirs_work_node * work = args->work;
1734     char *dir = args->dir;
1735     char *filename = args->filename;
1736
1737     code = _namei_examine_file(work, dir, filename);
1738
1739     *(args->result) = code;
1740
1741     if (code < 0) {
1742         *(work->error) = 1;
1743         /* we've errored, so no point in letting more jobs continue */
1744         afs_wq_shutdown(queue);
1745     }
1746
1747     return 0;
1748 }
1749
1750 static pthread_once_t wq_once = PTHREAD_ONCE_INIT;
1751 static pthread_key_t wq_key;
1752
1753 /**
1754  * create the wq_key key for storing a work queue.
1755  */
1756 static void
1757 _namei_wq_keycreate(void)
1758 {
1759     osi_Assert(pthread_key_create(&wq_key, NULL) == 0);
1760 }
1761
1762 /**
1763  * set the work queue for this thread to use for backgrounding namei ops.
1764  *
1765  * The work queue will be used in ListAFSSubdirs (called indirectly by
1766  * ListViceInodes) to examine files in parallel.
1767  *
1768  * @param[in] wq  the work queue to use
1769  */
1770 void
1771 namei_SetWorkQueue(struct afs_work_queue *wq)
1772 {
1773     osi_Assert(pthread_once(&wq_once, _namei_wq_keycreate) == 0);
1774
1775     osi_Assert(pthread_setspecific(wq_key, wq) == 0);
1776 }
1777
1778 /**
1779  * enqueue an examine file work unit.
1780  *
1781  * @param[in] work     the _namei_examine_file arguments that are common to
1782  *                     all callers within the same ListAFSFiles operation
1783  * @param[in] dir      the specific directory to look at (string will be
1784  *                     copied; can be stack/temporary memory)
1785  * @param[in] filename the filename to look at (string will be copied; can be
1786  *                     stack/temporary memory)
1787  * @param[in] wq       work queue to enqueue this work unit to
1788  * @param[in] resultlist the list to append the 'struct listsubdirs_result' to
1789  *                       for the enqueued work unit
1790  *
1791  * @return operation status
1792  *    @retval 0 success
1793  *    @retval -1 fatal error
1794  *
1795  * @note errors MUST be indicated by a -1 error code and nothing else, to be
1796  *       compatible with _namei_examine_reg and _namei_examine_special
1797  *
1798  * @internal
1799  */
1800 static int
1801 _namei_examine_file_spawn(const struct listsubdirs_work_node *work,
1802                           const char *dir, const char *filename,
1803                           struct afs_work_queue *wq,
1804                           struct rx_queue *resultlist)
1805 {
1806     int code, ret = 0;
1807     struct listsubdirs_args *args = NULL;
1808     struct listsubdirs_result *result = NULL;
1809     struct afs_work_queue_node *node = NULL;
1810     struct afs_work_queue_add_opts opts;
1811
1812     args = malloc(sizeof(*args));
1813     if (args == NULL) {
1814         ret = -1;
1815         goto error;
1816     }
1817
1818     result = malloc(sizeof(*result));
1819     if (result == NULL) {
1820         ret = -1;
1821         goto error;
1822     }
1823
1824     code = afs_wq_node_alloc(&node);
1825     if (code) {
1826         ret = -1;
1827         goto error;
1828     }
1829     code = afs_wq_node_set_detached(node);
1830     if (code) {
1831         ret = -1;
1832         goto error;
1833     }
1834
1835     args->work = work;
1836     args->result = &result->inodes;
1837     strlcpy(args->dir, dir, sizeof(args->dir));
1838     strlcpy(args->filename, filename, sizeof(args->filename));
1839
1840     code = afs_wq_node_set_callback(node,
1841                                          &_namei_examine_file_cbk,
1842                                          args, &free);
1843     if (code) {
1844         ret = -1;
1845         goto error;
1846     }
1847     args = NULL;
1848
1849     afs_wq_add_opts_init(&opts);
1850     opts.donate = 1;
1851
1852     code = afs_wq_add(wq, node, &opts);
1853     if (code) {
1854         ret = -1;
1855         goto error;
1856     }
1857     node = NULL;
1858
1859     queue_Append(resultlist, result);
1860     result = NULL;
1861
1862  error:
1863     if (node) {
1864         afs_wq_node_put(node);
1865         node = NULL;
1866     }
1867     if (args) {
1868         free(args);
1869         args = NULL;
1870     }
1871     if (result) {
1872         free(result);
1873         result = NULL;
1874     }
1875
1876     return ret;
1877 }
1878
1879 /*@}*/
1880 #else /* !AFS_SALSRV_ENV */
1881 # define _namei_examine_file_spawn(work, dir, file, wq, resultlist) \
1882          _namei_examine_file(work, dir, file)
1883 #endif /* !AFS_SALSRV_ENV */
1884
1885 /**
1886  * traverse and check inodes.
1887  *
1888  * @param[in] dirIH               volume group directory handle
1889  * @param[in] writeFun            function pointer which will write inode
1890  *                                metadata to FILE stream fp
1891  * @param[in] fp                  file stream where inode metadata gets
1892  *                                written
1893  * @param[in] judgeFun            inode filter function.  if not NULL, only
1894  *                                inodes for which the filter returns non-zero
1895  *                                will be written out by writeFun
1896  * @param[in] singleVolumeNumber  volume id filter.  only inodes matching this
1897  *                                filter are written out by writeFun
1898  * @param[in] rock                opaque pointer passed to judgeFun and writeFun
1899  *
1900  * @return operation status
1901  *    @retval <0 error
1902  *    @retval >=0 number of matching inodes found
1903  *
1904  * @todo the salsrv implementation may consume a lot of
1905  *       memory for a large volume.  at some point we should
1906  *       probably write a background thread to asynchronously
1907  *       clean up the resultlist nodes to reduce memory footprint
1908  *
1909  * @internal
1910  */
1911 static int
1912 namei_ListAFSSubDirs(IHandle_t * dirIH,
1913                      int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
1914                                       char *),
1915                      FILE * fp,
1916                      int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *),
1917                      afs_uint32 singleVolumeNumber, void *rock)
1918 {
1919     int code = 0, ret = 0;
1920     IHandle_t myIH = *dirIH;
1921     namei_t name;
1922     char path1[512], path2[512], path3[512];
1923     DIR *dirp1, *dirp2, *dirp3;
1924     struct dirent *dp1, *dp2, *dp3;
1925     FdHandle_t linkHandle;
1926     int ninodes = 0;
1927     struct listsubdirs_work_node work;
1928 #ifdef AFS_SALSRV_ENV
1929     int error = 0;
1930     struct afs_work_queue *wq;
1931     int wq_up = 0;
1932     struct rx_queue resultlist;
1933 #endif
1934 #ifdef DELETE_ZLC
1935     int i;
1936     static void AddToZLCDeleteList(char dir, char *name);
1937     static void DeleteZLCFiles(char *path);
1938 #endif
1939
1940     namei_HandleToVolDir(&name, &myIH);
1941     strlcpy(path1, name.n_path, sizeof(path1));
1942
1943     /* Do the directory containing the special files first to pick up link
1944      * counts.
1945      */
1946     (void)strcat(path1, "/");
1947     (void)strcat(path1, NAMEI_SPECDIR);
1948
1949     linkHandle.fd_fd = -1;
1950 #ifdef AFS_SALSRV_ENV
1951     osi_Assert(pthread_once(&wq_once, _namei_wq_keycreate) == 0);
1952
1953     wq = pthread_getspecific(wq_key);
1954     if (!wq) {
1955         ret = -1;
1956         goto error;
1957     }
1958     wq_up = 1;
1959     queue_Init(&resultlist);
1960 #endif
1961
1962     memset(&work, 0, sizeof(work));
1963     work.linkHandle = &linkHandle;
1964     work.IH = &myIH;
1965     work.fp = fp;
1966     work.writeFun = writeFun;
1967     work.judgeFun = judgeFun;
1968     work.singleVolumeNumber = singleVolumeNumber;
1969     work.rock = rock;
1970     work.special = 1;
1971 #ifdef AFS_SALSRV_ENV
1972     work.error = &error;
1973 #endif
1974
1975     dirp1 = opendir(path1);
1976     if (dirp1) {
1977         while ((dp1 = readdir(dirp1))) {
1978             if (*dp1->d_name == '.')
1979                 continue;
1980
1981 #ifdef AFS_SALSRV_ENV
1982             if (error) {
1983                 closedir(dirp1);
1984                 ret = -1;
1985                 goto error;
1986             }
1987 #endif /* AFS_SALSRV_ENV */
1988
1989             code = _namei_examine_file_spawn(&work, path1, dp1->d_name, wq, &resultlist);
1990
1991             switch (code) {
1992             case -1:
1993                 /* fatal error */
1994                 closedir(dirp1);
1995                 ret = -1;
1996                 goto error;
1997
1998             case 1:
1999                 /* count this inode */
2000 #ifndef AFS_SALSRV_ENV
2001                 ninodes++;
2002 #endif
2003                 break;
2004             }
2005         }
2006         closedir(dirp1);
2007     }
2008
2009 #ifdef AFS_SALSRV_ENV
2010     /* effectively a barrier */
2011     code = _namei_listsubdirs_wait(wq, &resultlist);
2012     if (code < 0 || error) {
2013         ret = -1;
2014         goto error;
2015     }
2016     error = 0;
2017     ninodes += code;
2018 #endif
2019
2020     /* Now run through all the other subdirs */
2021     namei_HandleToVolDir(&name, &myIH);
2022     strlcpy(path1, name.n_path, sizeof(path1));
2023
2024     work.special = 0;
2025
2026     dirp1 = opendir(path1);
2027     if (dirp1) {
2028         while ((dp1 = readdir(dirp1))) {
2029             if (*dp1->d_name == '.')
2030                 continue;
2031             if (!strcmp(dp1->d_name, NAMEI_SPECDIR))
2032                 continue;
2033
2034             /* Now we've got a next level subdir. */
2035             afs_snprintf(path2, sizeof(path2), "%s/%s", path1, dp1->d_name);
2036             dirp2 = opendir(path2);
2037             if (dirp2) {
2038                 while ((dp2 = readdir(dirp2))) {
2039                     if (*dp2->d_name == '.')
2040                         continue;
2041
2042                     /* Now we've got to the actual data */
2043                     afs_snprintf(path3, sizeof(path3), "%s/%s", path2,
2044                                  dp2->d_name);
2045
2046                     dirp3 = opendir(path3);
2047                     if (dirp3) {
2048                         while ((dp3 = readdir(dirp3))) {
2049                             if (*dp3->d_name == '.')
2050                                 continue;
2051
2052 #ifdef AFS_SALSRV_ENV
2053                             if (error) {
2054                                 closedir(dirp3);
2055                                 closedir(dirp2);
2056                                 closedir(dirp1);
2057                                 ret = -1;
2058                                 goto error;
2059                             }
2060 #endif /* AFS_SALSRV_ENV */
2061
2062                             code = _namei_examine_file_spawn(&work, path3,
2063                                                              dp3->d_name, wq,
2064                                                              &resultlist);
2065
2066                             switch (code) {
2067                             case -1:
2068                                 closedir(dirp3);
2069                                 closedir(dirp2);
2070                                 closedir(dirp1);
2071                                 ret = -1;
2072                                 goto error;
2073
2074                             case 1:
2075 #ifndef AFS_SALSRV_ENV
2076                                 ninodes++;
2077 #endif
2078                                 break;
2079                             }
2080                         }
2081                         closedir(dirp3);
2082                     }
2083                 }
2084                 closedir(dirp2);
2085             }
2086         }
2087         closedir(dirp1);
2088     }
2089
2090 #ifdef AFS_SALSRV_ENV
2091     /* effectively a barrier */
2092     code = _namei_listsubdirs_wait(wq, &resultlist);
2093     if (code < 0 || error) {
2094         ret = -1;
2095         goto error;
2096     }
2097     error = 0;
2098     ninodes += code;
2099     wq_up = 0;
2100 #endif
2101
2102     if (!ninodes) {
2103         /* Then why does this directory exist? Blow it away. */
2104         namei_HandleToVolDir(&name, dirIH);
2105         namei_RemoveDataDirectories(&name);
2106     }
2107
2108  error:
2109 #ifdef AFS_SALSRV_ENV
2110     if (wq_up) {
2111         afs_wq_wait_all(wq);
2112     }
2113     _namei_listsubdirs_cleanup_results(&resultlist);
2114 #endif
2115     if (linkHandle.fd_fd >= 0)
2116         close(linkHandle.fd_fd);
2117
2118     if (!ret) {
2119         ret = ninodes;
2120     }
2121     return ret;
2122 }
2123
2124 /*@}*/
2125
2126 static int
2127 DecodeVolumeName(char *name, unsigned int *vid)
2128 {
2129     if (strlen(name) < 1)
2130         return -1;
2131     *vid = (unsigned int)flipbase64_to_int64(name);
2132     return 0;
2133 }
2134
2135
2136 /* DecodeInode
2137  *
2138  * Get the inode number from the name.
2139  * Get
2140  */
2141 static int
2142 DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
2143             unsigned int volid)
2144 {
2145     char fpath[512];
2146     struct afs_stat status;
2147     int parm, tag;
2148     lb64_string_t check;
2149
2150     afs_snprintf(fpath, sizeof(fpath), "%s/%s", dpath, name);
2151
2152     if (afs_stat(fpath, &status) < 0) {
2153         return -1;
2154     }
2155
2156     info->byteCount = status.st_size;
2157     info->inodeNumber = (Inode) flipbase64_to_int64(name);
2158
2159     int64_to_flipbase64(check, info->inodeNumber);
2160     if (strcmp(name, check))
2161         return -1;
2162
2163     GetOGMFromStat(&status, &parm, &tag);
2164     if ((info->inodeNumber & NAMEI_INODESPECIAL) == NAMEI_INODESPECIAL) {
2165         /* p1 - vid, p2 - -1, p3 - type, p4 - rwvid */
2166         info->u.param[0] = parm;
2167         info->u.param[1] = -1;
2168         info->u.param[2] = tag;
2169         info->u.param[3] = volid;
2170     } else {
2171         /* p1 - vid, p2 - vno, p3 - uniq, p4 - dv */
2172         info->u.param[0] = volid;
2173         info->u.param[1] = (int)(info->inodeNumber & NAMEI_VNODEMASK);
2174         info->u.param[2] = (int)((info->inodeNumber >> NAMEI_UNIQSHIFT)
2175                                  & (Inode) NAMEI_UNIQMASK);
2176         info->u.param[3] = parm;
2177     }
2178     return 0;
2179 }
2180
2181 /*
2182  * Convert the VolumeInfo file from RO to RW
2183  * this routine is called by namei_convertROtoRWvolume()
2184  */
2185
2186 #ifdef FSSYNC_BUILD_CLIENT
2187 static afs_int32
2188 convertVolumeInfo(int fdr, int fdw, afs_uint32 vid)
2189 {
2190     struct VolumeDiskData vd;
2191     char *p;
2192
2193     if (read(fdr, &vd, sizeof(struct VolumeDiskData)) !=
2194         sizeof(struct VolumeDiskData)) {
2195         Log("1 convertVolumeInfo: read failed for %lu with code %d\n",
2196             afs_printable_uint32_lu(vid),
2197             errno);
2198         return -1;
2199     }
2200     vd.restoredFromId = vd.id;  /* remember the RO volume here */
2201     vd.cloneId = vd.id;
2202     vd.id = vd.parentId;
2203     vd.type = RWVOL;
2204     vd.dontSalvage = 0;
2205     vd.inUse = 0;
2206     vd.uniquifier += 5000;      /* just in case there are still file copies from
2207                                  * the old RW volume around */
2208     p = strrchr(vd.name, '.');
2209     if (p && !strcmp(p, ".readonly")) {
2210         memset(p, 0, 9);
2211     }
2212     if (write(fdw, &vd, sizeof(struct VolumeDiskData)) !=
2213         sizeof(struct VolumeDiskData)) {
2214         Log("1 convertVolumeInfo: write failed for %lu with code %d\n",
2215             afs_printable_uint32_lu(vid),
2216             errno);
2217         return -1;
2218     }
2219     return 0;
2220 }
2221 #endif
2222
2223 /*
2224  * Convert a RO-volume into a RW-volume
2225  *
2226  * This function allows to recover very fast from the loss of a partition
2227  * from RO-copies if all RO-Copies exist on another partition.
2228  * Then these RO-volumes can be made to the new RW-volumes.
2229  * Backup of RW-volumes then consists in "vos release".
2230  *
2231  * We must make sure in this partition exists only the RO-volume which
2232  * is typical for remote replicas.
2233  *
2234  * Then the linktable is already ok,
2235  *      the vnode files need to be renamed
2236  *      the volinfo file needs to be replaced by another one with
2237  *                      slightly different contents and new name.
2238  * The volume header file of the RO-volume in the /vicep<x> directory
2239  * is destroyed by this call. A new header file for the RW-volume must
2240  * be created after return from this routine.
2241  */
2242
2243 int
2244 namei_ConvertROtoRWvolume(char *pname, afs_uint32 volumeId)
2245 {
2246     int code = 0;
2247 #ifdef FSSYNC_BUILD_CLIENT
2248     namei_t n;
2249     char dir_name[512], oldpath[512], newpath[512];
2250     char smallName[64];
2251     char largeName[64];
2252     char infoName[64];
2253     IHandle_t t_ih;
2254     IHandle_t *ih;
2255     char infoSeen = 0;
2256     char smallSeen = 0;
2257     char largeSeen = 0;
2258     char linkSeen = 0;
2259     int fd, fd2;
2260     char *p;
2261     DIR *dirp;
2262     Inode ino;
2263     struct dirent *dp;
2264     struct DiskPartition64 *partP;
2265     struct ViceInodeInfo info;
2266     struct VolumeDiskHeader h;
2267 # ifdef AFS_DEMAND_ATTACH_FS
2268     int locktype = 0;
2269 # endif /* AFS_DEMAND_ATTACH_FS */
2270
2271     for (partP = DiskPartitionList; partP && strcmp(partP->name, pname);
2272          partP = partP->next);
2273     if (!partP) {
2274         Log("1 namei_ConvertROtoRWvolume: Couldn't find DiskPartition for %s\n", pname);
2275         code = EIO;
2276         goto done;
2277     }
2278
2279 # ifdef AFS_DEMAND_ATTACH_FS
2280     locktype = VVolLockType(V_VOLUPD, 1);
2281     code = VLockVolumeByIdNB(volumeId, partP, locktype);
2282     if (code) {
2283         locktype = 0;
2284         code = EIO;
2285         goto done;
2286     }
2287 # endif /* AFS_DEMAND_ATTACH_FS */
2288
2289     if (VReadVolumeDiskHeader(volumeId, partP, &h)) {
2290         Log("1 namei_ConvertROtoRWvolume: Couldn't read header for RO-volume %lu.\n",
2291             afs_printable_uint32_lu(volumeId));
2292         code = EIO;
2293         goto done;
2294     }
2295
2296     FSYNC_VolOp(volumeId, pname, FSYNC_VOL_BREAKCBKS, 0, NULL);
2297
2298     ino = namei_MakeSpecIno(h.parent, VI_LINKTABLE);
2299     IH_INIT(ih, partP->device, h.parent, ino);
2300
2301     namei_HandleToName(&n, ih);
2302     strlcpy(dir_name, n.n_path, sizeof(dir_name));
2303     p = strrchr(dir_name, '/');
2304     *p = 0;
2305     dirp = opendir(dir_name);
2306     if (!dirp) {
2307         Log("1 namei_ConvertROtoRWvolume: Could not opendir(%s)\n", dir_name);
2308         code = EIO;
2309         goto done;
2310     }
2311
2312     while ((dp = readdir(dirp))) {
2313         /* struct ViceInodeInfo info; */
2314
2315         if (*dp->d_name == '.')
2316             continue;
2317         if (DecodeInode(dir_name, dp->d_name, &info, ih->ih_vid) < 0) {
2318             Log("1 namei_ConvertROtoRWvolume: DecodeInode failed for %s/%s\n",
2319                 dir_name, dp->d_name);
2320             closedir(dirp);
2321             code = -1;
2322             goto done;
2323         }
2324         if (info.u.param[1] != -1) {
2325             Log("1 namei_ConvertROtoRWvolume: found other than volume special file %s/%s\n", dir_name, dp->d_name);
2326             closedir(dirp);
2327             code = -1;
2328             goto done;
2329         }
2330         if (info.u.param[0] != volumeId) {
2331             if (info.u.param[0] == ih->ih_vid) {
2332                 if (info.u.param[2] == VI_LINKTABLE) {  /* link table */
2333                     linkSeen = 1;
2334                     continue;
2335                 }
2336             }
2337             Log("1 namei_ConvertROtoRWvolume: found special file %s/%s"
2338                 " for volume %lu\n", dir_name, dp->d_name,
2339                 afs_printable_uint32_lu(info.u.param[0]));
2340             closedir(dirp);
2341             code = VVOLEXISTS;
2342             goto done;
2343         }
2344         if (info.u.param[2] == VI_VOLINFO) {    /* volume info file */
2345             strlcpy(infoName, dp->d_name, sizeof(infoName));
2346             infoSeen = 1;
2347         } else if (info.u.param[2] == VI_SMALLINDEX) {  /* small vnodes file */
2348             strlcpy(smallName, dp->d_name, sizeof(smallName));
2349             smallSeen = 1;
2350         } else if (info.u.param[2] == VI_LARGEINDEX) {  /* large vnodes file */
2351             strlcpy(largeName, dp->d_name, sizeof(largeName));
2352             largeSeen = 1;
2353         } else {
2354             closedir(dirp);
2355             Log("1 namei_ConvertROtoRWvolume: unknown type %d of special file found : %s/%s\n", info.u.param[2], dir_name, dp->d_name);
2356             code = -1;
2357             goto done;
2358         }
2359     }
2360     closedir(dirp);
2361
2362     if (!infoSeen || !smallSeen || !largeSeen || !linkSeen) {
2363         Log("1 namei_ConvertROtoRWvolume: not all special files found in %s\n", dir_name);
2364         code = -1;
2365         goto done;
2366     }
2367
2368     /*
2369      * If we come here then there was only a RO-volume and we can safely
2370      * proceed.
2371      */
2372
2373     memset(&t_ih, 0, sizeof(t_ih));
2374     t_ih.ih_dev = ih->ih_dev;
2375     t_ih.ih_vid = ih->ih_vid;
2376
2377     (void)afs_snprintf(oldpath, sizeof oldpath, "%s/%s", dir_name, infoName);
2378     fd = afs_open(oldpath, O_RDWR, 0);
2379     if (fd < 0) {
2380         Log("1 namei_ConvertROtoRWvolume: could not open RO info file: %s\n",
2381             oldpath);
2382         code = -1;
2383         goto done;
2384     }
2385     t_ih.ih_ino = namei_MakeSpecIno(ih->ih_vid, VI_VOLINFO);
2386     namei_HandleToName(&n, &t_ih);
2387     fd2 = afs_open(n.n_path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0);
2388     if (fd2 < 0) {
2389         Log("1 namei_ConvertROtoRWvolume: could not create RW info file: %s\n", n.n_path);
2390         close(fd);
2391         code = -1;
2392         goto done;
2393     }
2394     code = convertVolumeInfo(fd, fd2, ih->ih_vid);
2395     close(fd);
2396     if (code) {
2397         close(fd2);
2398         unlink(n.n_path);
2399         code = -1;
2400         goto done;
2401     }
2402     SetOGM(fd2, ih->ih_vid, 1);
2403     close(fd2);
2404
2405     t_ih.ih_ino = namei_MakeSpecIno(ih->ih_vid, VI_SMALLINDEX);
2406     namei_HandleToName(&n, &t_ih);
2407     (void)afs_snprintf(newpath, sizeof newpath, "%s/%s", dir_name, smallName);
2408     fd = afs_open(newpath, O_RDWR, 0);
2409     if (fd < 0) {
2410         Log("1 namei_ConvertROtoRWvolume: could not open SmallIndex file: %s\n", newpath);
2411         code = -1;
2412         goto done;
2413     }
2414     SetOGM(fd, ih->ih_vid, 2);
2415     close(fd);
2416     link(newpath, n.n_path);
2417     unlink(newpath);
2418
2419     t_ih.ih_ino = namei_MakeSpecIno(ih->ih_vid, VI_LARGEINDEX);
2420     namei_HandleToName(&n, &t_ih);
2421     (void)afs_snprintf(newpath, sizeof newpath, "%s/%s", dir_name, largeName);
2422     fd = afs_open(newpath, O_RDWR, 0);
2423     if (fd < 0) {
2424         Log("1 namei_ConvertROtoRWvolume: could not open LargeIndex file: %s\n", newpath);
2425         code = -1;
2426         goto done;
2427     }
2428     SetOGM(fd, ih->ih_vid, 3);
2429     close(fd);
2430     link(newpath, n.n_path);
2431     unlink(newpath);
2432
2433     unlink(oldpath);
2434
2435     h.id = h.parent;
2436     h.volumeInfo_hi = h.id;
2437     h.smallVnodeIndex_hi = h.id;
2438     h.largeVnodeIndex_hi = h.id;
2439     h.linkTable_hi = h.id;
2440
2441     if (VCreateVolumeDiskHeader(&h, partP)) {
2442         Log("1 namei_ConvertROtoRWvolume: Couldn't write header for RW-volume %lu\n",
2443             afs_printable_uint32_lu(h.id));
2444         code = EIO;
2445         goto done;
2446     }
2447
2448     if (VDestroyVolumeDiskHeader(partP, volumeId, h.parent)) {
2449         Log("1 namei_ConvertROtoRWvolume: Couldn't unlink header for RO-volume %lu\n",
2450             afs_printable_uint32_lu(volumeId));
2451     }
2452
2453     FSYNC_VolOp(volumeId, pname, FSYNC_VOL_DONE, 0, NULL);
2454     FSYNC_VolOp(h.id, pname, FSYNC_VOL_ON, 0, NULL);
2455
2456  done:
2457 # ifdef AFS_DEMAND_ATTACH_FS
2458     if (locktype) {
2459         VUnlockVolumeById(volumeId, partP);
2460     }
2461 # endif /* AFS_DEMAND_ATTACH_FS */
2462 #endif
2463
2464     return code;
2465 }
2466
2467 /* PrintInode
2468  *
2469  * returns a static string used to print either 32 or 64 bit inode numbers.
2470  */
2471 char *
2472 PrintInode(char *s, Inode ino)
2473 {
2474     static afs_ino_str_t result;
2475     if (!s)
2476         s = result;
2477
2478     (void)afs_snprintf(s, sizeof(afs_ino_str_t), "%llu", (afs_uintmax_t) ino);
2479
2480     return s;
2481 }
2482
2483
2484 #ifdef DELETE_ZLC
2485 /* Routines to facilitate removing zero link count files. */
2486 #define MAX_ZLC_NAMES 32
2487 #define MAX_ZLC_NAMELEN 16
2488 typedef struct zlcList_s {
2489     struct zlcList_s *zlc_next;
2490     int zlc_n;
2491     char zlc_names[MAX_ZLC_NAMES][MAX_ZLC_NAMELEN];
2492 } zlcList_t;
2493
2494 static zlcList_t *zlcAnchor = NULL;
2495 static zlcList_t *zlcCur = NULL;
2496
2497 static void
2498 AddToZLCDeleteList(char dir, char *name)
2499 {
2500     osi_Assert(strlen(name) <= MAX_ZLC_NAMELEN - 3);
2501
2502     if (!zlcCur || zlcCur->zlc_n >= MAX_ZLC_NAMES) {
2503         if (zlcCur && zlcCur->zlc_next)
2504             zlcCur = zlcCur->zlc_next;
2505         else {
2506             zlcList_t *tmp = (zlcList_t *) malloc(sizeof(zlcList_t));
2507             if (!tmp)
2508                 return;
2509             if (!zlcAnchor) {
2510                 zlcAnchor = tmp;
2511             } else {
2512                 zlcCur->zlc_next = tmp;
2513             }
2514             zlcCur = tmp;
2515             zlcCur->zlc_n = 0;
2516             zlcCur->zlc_next = NULL;
2517         }
2518     }
2519
2520     (void)sprintf(zlcCur->zlc_names[zlcCur->zlc_n], "%c\\%s", dir, name);
2521     zlcCur->zlc_n++;
2522 }
2523
2524 static void
2525 DeleteZLCFiles(char *path)
2526 {
2527     zlcList_t *z;
2528     int i;
2529     char fname[1024];
2530
2531     for (z = zlcAnchor; z; z = z->zlc_next) {
2532         for (i = 0; i < z->zlc_n; i++) {
2533             (void)sprintf(fname, "%s\\%s", path, z->zlc_names[i]);
2534             if (namei_unlink(fname) < 0) {
2535                 Log("ZLC: Can't unlink %s, dos error = %d\n", fname,
2536                     GetLastError());
2537             }
2538         }
2539         z->zlc_n = 0;           /* Can reuse space. */
2540     }
2541     zlcCur = zlcAnchor;
2542 }
2543
2544 static void
2545 FreeZLCList(void)
2546 {
2547     zlcList_t *tnext;
2548     zlcList_t *i;
2549
2550     i = zlcAnchor;
2551     while (i) {
2552         tnext = i->zlc_next;
2553         free(i);
2554         i = tnext;
2555     }
2556     zlcCur = zlcAnchor = NULL;
2557 }
2558 #endif
2559
2560 #endif /* AFS_NAMEI_ENV */