46efbdd1e8f8f24d9f527321dcd4e1aadf826da6
[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/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 <afs/errors.h>
44
45 /*@+fcnmacros +macrofcndecl@*/
46 #ifdef O_LARGEFILE
47 #ifdef S_SPLINT_S
48 extern off64_t afs_lseek(int FD, off64_t O, int F);
49 #endif /*S_SPLINT_S */
50 #define afs_lseek(FD, O, F)     lseek64(FD, (off64_t)(O), F)
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 extern off_t afs_lseek(int FD, off_t O, int F);
58 #endif /*S_SPLINT_S */
59 #define afs_lseek(FD, O, F)     lseek(FD, (off_t)(O), F)
60 #define afs_stat                stat
61 #define afs_fstat               fstat
62 #define afs_open                open
63 #define afs_fopen               fopen
64 #endif /* !O_LARGEFILE */
65 /*@=fcnmacros =macrofcndecl@*/
66
67 /*@printflike@*/ extern void Log(const char *format, ...);
68
69 #ifndef LOCK_SH
70 #define   LOCK_SH   1    /* shared lock */
71 #define   LOCK_EX   2    /* exclusive lock */
72 #define   LOCK_NB   4    /* don't block when locking */
73 #define   LOCK_UN   8    /* unlock */
74 #endif
75
76 #ifndef HAVE_FLOCK
77 #include <fcntl.h>
78
79 /*
80  * This function emulates a subset of flock()
81  */
82 int 
83 emul_flock(int fd, int cmd)
84 {    struct flock f;
85
86     memset(&f, 0, sizeof (f));
87
88     if (cmd & LOCK_UN)
89         f.l_type = F_UNLCK;
90     if (cmd & LOCK_SH)
91         f.l_type = F_RDLCK;
92     if (cmd & LOCK_EX)
93         f.l_type = F_WRLCK;
94
95     return fcntl(fd, (cmd & LOCK_NB) ? F_SETLK : F_SETLKW, &f);
96 }
97
98 #define flock(f,c)      emul_flock(f,c)
99 #endif
100
101 extern char *volutil_PartitionName_r(int volid, char *buf, int buflen);
102 int Testing=0;
103
104
105 afs_sfsize_t
106 namei_iread(IHandle_t * h, afs_foff_t offset, char *buf, afs_fsize_t size)
107 {
108     afs_sfsize_t nBytes;
109     FdHandle_t *fdP;
110
111     fdP = IH_OPEN(h);
112     if (fdP == NULL)
113         return -1;
114
115     if (FDH_SEEK(fdP, offset, SEEK_SET) < 0) {
116         FDH_REALLYCLOSE(fdP);
117         return -1;
118     }
119
120     nBytes = FDH_READ(fdP, buf, size);
121     FDH_CLOSE(fdP);
122     return nBytes;
123 }
124
125 afs_sfsize_t
126 namei_iwrite(IHandle_t * h, afs_foff_t offset, char *buf, afs_fsize_t size)
127 {
128     afs_sfsize_t nBytes;
129     FdHandle_t *fdP;
130
131     fdP = IH_OPEN(h);
132     if (fdP == NULL)
133         return -1;
134
135     if (FDH_SEEK(fdP, offset, SEEK_SET) < 0) {
136         FDH_REALLYCLOSE(fdP);
137         return -1;
138     }
139     nBytes = FDH_WRITE(fdP, buf, size);
140     FDH_CLOSE(fdP);
141     return nBytes;
142 }
143
144
145
146 /* Inode number format:
147  * low 26 bits - vnode number - all 1's if volume special file.
148  * next 3 bits - tag 
149  * next 3 bits spare (0's)
150  * high 32 bits - uniquifier (regular) or type if spare
151  */
152 #define NAMEI_VNODEMASK    0x003ffffff
153 #define NAMEI_TAGMASK      0x7
154 #define NAMEI_TAGSHIFT     26
155 #define NAMEI_UNIQMASK     0xffffffff
156 #define NAMEI_UNIQSHIFT    32
157 #define NAMEI_INODESPECIAL ((Inode)NAMEI_VNODEMASK)
158 #define NAMEI_VNODESPECIAL NAMEI_VNODEMASK
159
160 /* dir1 is the high 8 bits of the 26 bit vnode */
161 #define VNO_DIR1(vno) ((vno >> 14) & 0xff)
162 /* dir2 is the next 9 bits */
163 #define VNO_DIR2(vno) ((vno >> 9) & 0x1ff)
164 /* "name" is the low 9 bits of the vnode, the 3 bit tag and the uniq */
165
166 #define NAMEI_SPECDIR "special"
167 #define NAMEI_SPECDIRLEN (sizeof(NAMEI_SPECDIR)-1)
168
169 #define NAMEI_MAXVOLS 5         /* Maximum supported number of volumes per volume
170                                  * group, not counting temporary (move) volumes.
171                                  * This is the number of separate files, all having
172                                  * the same vnode number, which can occur in a volume
173                                  * group at once.
174                                  */
175
176
177 typedef struct {
178     int ogm_owner;
179     int ogm_group;
180     int ogm_mode;
181 } namei_ogm_t;
182
183 static int namei_GetLinkCount2(FdHandle_t * h, Inode ino, int lockit, int fixup, int nowrite);
184
185 static int GetFreeTag(IHandle_t * ih, int vno);
186
187 /* namei_HandleToInodeDir
188  *
189  * Construct the path name of the directory holding the inode data.
190  * Format: /<vicepx>/INODEDIR
191  *
192  */
193 #define PNAME_BLEN 64
194 static void
195 namei_HandleToInodeDir(namei_t * name, IHandle_t * ih)
196 {
197     char *tmp = name->n_base;
198
199     memset(name, '\0', sizeof(*name));
200
201     (void)volutil_PartitionName_r(ih->ih_dev, tmp, NAMEI_LCOMP_LEN);
202     tmp += VICE_PREFIX_SIZE;
203     tmp += ih->ih_dev > 25 ? 2 : 1;
204     *tmp = '/';
205     tmp++;
206     (void)strcpy(tmp, INODEDIR);
207     (void)strcpy(name->n_path, name->n_base);
208 }
209
210 #define addtoname(N, C) \
211 do { \
212          strcat((N)->n_path, "/"); strcat((N)->n_path, C); \
213 } while(0)
214
215
216 static void
217 namei_HandleToVolDir(namei_t * name, IHandle_t * ih)
218 {
219     lb64_string_t tmp;
220
221     namei_HandleToInodeDir(name, ih);
222     (void)int32_to_flipbase64(tmp, (int64_t) (ih->ih_vid & 0xff));
223     (void)strcpy(name->n_voldir1, tmp);
224     addtoname(name, name->n_voldir1);
225     (void)int32_to_flipbase64(tmp, (int64_t) ih->ih_vid);
226     (void)strcpy(name->n_voldir2, tmp);
227     addtoname(name, name->n_voldir2);
228 }
229
230 /* namei_HandleToName
231  *
232  * Constructs a file name for the fully qualified handle.
233  * Note that special files end up in /vicepX/InodeDir/Vxx/V*.data/special
234  */
235 void
236 namei_HandleToName(namei_t * name, IHandle_t * ih)
237 {
238     lb64_string_t str;
239     int vno = (int)(ih->ih_ino & NAMEI_VNODEMASK);
240
241     namei_HandleToVolDir(name, ih);
242
243     if (vno == NAMEI_VNODESPECIAL) {
244         (void)strcpy(name->n_dir1, NAMEI_SPECDIR);
245         addtoname(name, name->n_dir1);
246         name->n_dir2[0] = '\0';
247     } else {
248         (void)int32_to_flipbase64(str, VNO_DIR1(vno));
249         (void)strcpy(name->n_dir1, str);
250         addtoname(name, name->n_dir1);
251         (void)int32_to_flipbase64(str, VNO_DIR2(vno));
252         (void)strcpy(name->n_dir2, str);
253         addtoname(name, name->n_dir2);
254     }
255     (void)int64_to_flipbase64(str, (int64_t) ih->ih_ino);
256     (void)strcpy(name->n_inode, str);
257     addtoname(name, name->n_inode);
258 }
259
260 /* The following is a warning to tell sys-admins to not muck about in this
261  * name space.
262  */
263 #define VICE_README "These files and directories are a part of the AFS \
264 namespace. Modifying them\nin any way will result in loss of AFS data,\n\
265 ownership and permissions included.\n"
266 int
267 namei_ViceREADME(char *partition)
268 {
269     char filename[32];
270     int fd;
271
272     /* Create the inode directory if we're starting for the first time */
273     (void)afs_snprintf(filename, sizeof filename, "%s/%s", partition,
274                        INODEDIR);
275     mkdir(filename, 0700);
276
277     (void)afs_snprintf(filename, sizeof filename, "%s/%s/README", partition,
278                        INODEDIR);
279     fd = afs_open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0444);
280     if (fd >= 0) {
281         (void)write(fd, VICE_README, strlen(VICE_README));
282         close(fd);
283     }
284     return (errno);
285 }
286
287
288 #define create_dir() \
289 do { \
290     if (mkdir(tmp, 0700)<0) { \
291         if (errno != EEXIST) \
292             return -1; \
293     } \
294     else { \
295         *created = 1; \
296     } \
297 } while (0)
298
299 #define create_nextdir(A) \
300 do { \
301          strcat(tmp, "/"); strcat(tmp, A); create_dir();  \
302 } while(0)
303
304 /* namei_CreateDataDirectories
305  *
306  * If creating the file failed because of ENOENT or ENOTDIR, try
307  * creating all the directories first.
308  */
309 static int
310 namei_CreateDataDirectories(namei_t * name, int *created)
311 {
312     char tmp[256];
313
314     *created = 0;
315
316     (void)strcpy(tmp, name->n_base);
317     create_dir();
318
319     create_nextdir(name->n_voldir1);
320     create_nextdir(name->n_voldir2);
321     create_nextdir(name->n_dir1);
322     if (name->n_dir2[0]) {
323         create_nextdir(name->n_dir2);
324     }
325     return 0;
326 }
327
328 /* delTree(): Deletes an entire tree of directories (no files)
329  * Input:
330  *   root : Full path to the subtree. Should be big enough for PATH_MAX
331  *   tree : the subtree to be deleted is rooted here. Specifies only the
332  *          subtree beginning at tree (not the entire path). It should be
333  *          a pointer into the "root" buffer.
334  * Output:
335  *  errp : errno of the first error encountered during the directory cleanup.
336  *         *errp should have been initialized to 0.
337  * 
338  * Return Values:
339  *  -1  : If errors were encountered during cleanup and error is set to 
340  *        the first errno.
341  *   0  : Success.
342  *
343  * If there are errors, we try to work around them and delete as many
344  * directories as possible. We don't attempt to remove directories that still
345  * have non-dir entries in them.
346  */
347 static int
348 delTree(char *root, char *tree, int *errp)
349 {
350     char *cp;
351     DIR *ds;
352     struct dirent *dirp;
353     struct afs_stat st;
354
355     if (*tree) {
356         /* delete the children first */
357         cp = strchr(tree, '/');
358         if (cp) {
359             delTree(root, cp + 1, errp);
360             *cp = '\0';
361         } else
362             cp = tree + strlen(tree);   /* move cp to the end of string tree */
363
364         /* now delete all entries in this dir */
365         if ((ds = opendir(root)) != (DIR *) NULL) {
366             errno = 0;
367             while ((dirp = readdir(ds))) {
368                 /* ignore . and .. */
369                 if (!strcmp(dirp->d_name, ".") || !strcmp(dirp->d_name, ".."))
370                     continue;
371                 /* since root is big enough, we reuse the space to
372                  * concatenate the dirname to the current tree 
373                  */
374                 strcat(root, "/");
375                 strcat(root, dirp->d_name);
376                 if (afs_stat(root, &st) == 0 && S_ISDIR(st.st_mode)) {
377                     /* delete this subtree */
378                     delTree(root, cp + 1, errp);
379                 } else
380                     *errp = *errp ? *errp : errno;
381
382                 /* recover path to our cur tree by truncating it to 
383                  * its original len 
384                  */
385                 *cp = 0;
386             }
387             /* if (!errno) -- closedir not implicit if we got an error */
388             closedir(ds);
389         }
390
391         /* finally axe the current dir */
392         if (rmdir(root))
393             *errp = *errp ? *errp : errno;
394
395 #ifndef AFS_PTHREAD_ENV         /* let rx get some work done */
396         IOMGR_Poll();
397 #endif /* !AFS_PTHREAD_ENV */
398
399     }
400
401     /* if valid tree */
402     /* if we encountered errors during cleanup, we return a -1 */
403     if (*errp)
404         return -1;
405
406     return 0;
407
408 }
409
410 /* namei_RemoveDataDirectories
411  * Return Values:
412  * Returns 0 on success.
413  * Returns -1 on error. Typically, callers ignore this error bcause we
414  * can continue running if the removes fail. The salvage process will
415  * finish tidying up for us. We only use the n_base and n_voldir1 entries
416  * and only do rmdir's.
417  */
418
419 static int
420 namei_RemoveDataDirectories(namei_t * name)
421 {
422     char pbuf[MAXPATHLEN], *path = pbuf;
423     int prefixlen = strlen(name->n_base), err = 0;
424
425     strcpy(path, name->n_path);
426
427     /* move past the prefix */
428     path = path + prefixlen + 1;        /* skip over the trailing / */
429
430     /* now delete all dirs upto path */
431     return delTree(pbuf, path, &err);
432
433 }
434
435 /* Create the file in the name space.
436  *
437  * Parameters stored as follows:
438  * Regular files:
439  * p1 - volid - implied in containing directory.
440  * p2 - vnode - name is <vno:31-23>/<vno:22-15>/<vno:15-0><uniq:31-5><tag:2-0>
441  * p3 - uniq -- bits 4-0 are in mode bits 4-0
442  * p4 - dv ---- dv:15-0 in uid, dv:29-16 in gid, dv:31-30 in mode:6-5
443  * Special files:
444  * p1 - volid - creation time - dwHighDateTime
445  * p2 - vnode - -1 means special, file goes in "S" subdirectory.
446  * p3 - type -- name is <type>.<tag> where tag is a file name unqiquifier.
447  * p4 - parid - parent volume id - implied in containing directory.
448  *
449  * Return value is the inode number or (Inode)-1 if error.
450  * We "know" there is only one link table, so return EEXIST if there already
451  * is a link table. It's up to the calling code to test errno and increment
452  * the link count.
453  */
454
455 /* namei_MakeSpecIno
456  *
457  * This function is called by VCreateVolume to hide the implementation
458  * details of the inode numbers. This only allows for 7 volume special
459  * types, but if we get that far, this could should be dead by then.
460  */
461 Inode
462 namei_MakeSpecIno(int volid, int type)
463 {
464     Inode ino;
465     ino = NAMEI_INODESPECIAL;
466     type &= NAMEI_TAGMASK;
467     ino |= ((Inode) type) << NAMEI_TAGSHIFT;
468     ino |= ((Inode) volid) << NAMEI_UNIQSHIFT;
469     return ino;
470 }
471
472 /* SetOGM - set owner group and mode bits from parm and tag
473  *
474  * owner - low 15 bits of parm.
475  * group - next 15 bits of parm.
476  * mode - 2 bits of parm, then lowest = 3 bits of tag.
477  */
478 static int
479 SetOGM(int fd, int parm, int tag)
480 {
481     int owner, group, mode;
482
483     owner = parm & 0x7fff;
484     group = (parm >> 15) & 0x7fff;
485     if (fchown(fd, owner, group) < 0)
486         return -1;
487
488     mode = (parm >> 27) & 0x18;
489     mode |= tag & 0x7;
490     if (fchmod(fd, mode) < 0)
491         return -1;
492
493     return 0;
494
495 }
496
497 /* GetOGM - get parm and tag from owner, group and mode bits. */
498 static void
499 GetOGMFromStat(struct afs_stat *status, int *parm, int *tag)
500 {
501     *parm = status->st_uid | (status->st_gid << 15);
502     *parm |= (status->st_mode & 0x18) << 27;
503     *tag = status->st_mode & 0x7;
504 }
505
506 static int
507 GetOGM(int fd, int *parm, int *tag)
508 {
509     struct afs_stat status;
510     if (afs_fstat(fd, &status) < 0)
511         return -1;
512
513     GetOGMFromStat(&status, parm, tag);
514     return 0;
515 }
516
517 int big_vno = 0;                /* Just in case we ever do 64 bit vnodes. */
518
519 /* Derive the name and create it O_EXCL. If that fails we have an error.
520  * Get the tag from a free column in the link table.
521  */
522 Inode
523 namei_icreate(IHandle_t * lh, char *part, int p1, int p2, int p3, int p4)
524 {
525     namei_t name;
526     int fd = -1;
527     int code = 0;
528     int created_dir = 0;
529     IHandle_t tmp;
530     FdHandle_t *fdP;
531     FdHandle_t tfd;
532     int tag;
533     int ogm_parm;
534
535
536     memset((void *)&tmp, 0, sizeof(IHandle_t));
537
538
539     tmp.ih_dev = volutil_GetPartitionID(part);
540     if (tmp.ih_dev == -1) {
541         errno = EINVAL;
542         return -1;
543     }
544
545     if (p2 == -1) {
546         /* Parameters for special file:
547          * p1 - volume id - goes into owner/group/mode
548          * p2 - vnode == -1
549          * p3 - type
550          * p4 - parent volume id
551          */
552         ogm_parm = p1;
553         tag = p3;
554
555         tmp.ih_vid = p4;        /* Use parent volume id, where this file will be. */
556         tmp.ih_ino = namei_MakeSpecIno(p1, p3);
557     } else {
558         int vno = p2 & NAMEI_VNODEMASK;
559         /* Parameters for regular file:
560          * p1 - volume id
561          * p2 - vnode
562          * p3 - uniq
563          * p4 - dv
564          */
565
566         if (vno != p2) {
567             big_vno++;
568             errno = EINVAL;
569             return -1;
570         }
571         /* If GetFreeTag succeeds, it atomically sets link count to 1. */
572         tag = GetFreeTag(lh, p2);
573         if (tag < 0)
574             goto bad;
575
576         /* name is <uniq(p3)><tag><vno(p2)> */
577         tmp.ih_vid = p1;
578         tmp.ih_ino = (Inode) p2;
579         tmp.ih_ino |= ((Inode) tag) << NAMEI_TAGSHIFT;
580         tmp.ih_ino |= ((Inode) p3) << NAMEI_UNIQSHIFT;
581
582         ogm_parm = p4;
583     }
584
585     namei_HandleToName(&name, &tmp);
586     fd = afs_open(name.n_path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0);
587     if (fd < 0) {
588         if (errno == ENOTDIR || errno == ENOENT) {
589             if (namei_CreateDataDirectories(&name, &created_dir) < 0)
590                 goto bad;
591             fd = afs_open(name.n_path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR,
592                           0);
593             if (fd < 0)
594                 goto bad;
595         } else {
596             goto bad;
597         }
598     }
599     if (SetOGM(fd, ogm_parm, tag) < 0) {
600         close(fd);
601         fd = -1;
602         goto bad;
603     }
604
605     if (p2 == -1 && p3 == VI_LINKTABLE) {
606         /* hack at tmp to setup for set link count call. */
607         memset((void *)&tfd, 0, sizeof(FdHandle_t));    /* minimalistic still, but a little cleaner */
608         tfd.fd_ih = &tmp;
609         tfd.fd_fd = fd;
610         code = namei_SetLinkCount(&tfd, (Inode) 0, 1, 0);
611     }
612
613   bad:
614     if (fd >= 0)
615         close(fd);
616
617
618     if (code || (fd < 0)) {
619         if (p2 != -1) {
620             fdP = IH_OPEN(lh);
621             if (fdP) {
622                 namei_SetLinkCount(fdP, tmp.ih_ino, 0, 0);
623                 FDH_CLOSE(fdP);
624             }
625         }
626     }
627     return (code || (fd < 0)) ? (Inode) - 1 : tmp.ih_ino;
628 }
629
630
631 /* namei_iopen */
632 int
633 namei_iopen(IHandle_t * h)
634 {
635     int fd;
636     namei_t name;
637
638     /* Convert handle to file name. */
639     namei_HandleToName(&name, h);
640     fd = afs_open(name.n_path, O_RDWR, 0666);
641     return fd;
642 }
643
644 /* Need to detect vol special file and just unlink. In those cases, the
645  * handle passed in _is_ for the inode. We only check p1 for the special
646  * files.
647  */
648 int
649 namei_dec(IHandle_t * ih, Inode ino, int p1)
650 {
651     int count = 0;
652     namei_t name;
653     int code = 0;
654     FdHandle_t *fdP;
655
656     if ((ino & NAMEI_INODESPECIAL) == NAMEI_INODESPECIAL) {
657         IHandle_t *tmp;
658         int inode_p1, tag;
659         int type = (int)((ino >> NAMEI_TAGSHIFT) & NAMEI_TAGMASK);
660
661         /* Verify this is the right file. */
662         IH_INIT(tmp, ih->ih_dev, ih->ih_vid, ino);
663
664         fdP = IH_OPEN(tmp);
665         if (fdP == NULL) {
666             IH_RELEASE(tmp);
667             errno = EINVAL;
668             return -1;
669         }
670
671         if ((GetOGM(fdP->fd_fd, &inode_p1, &tag) < 0) || (inode_p1 != p1)) {
672             FDH_REALLYCLOSE(fdP);
673             IH_RELEASE(tmp);
674             errno = EINVAL;
675             return -1;
676         }
677
678         /* If it's the link table itself, decrement the link count. */
679         if (type == VI_LINKTABLE) {
680             if ((count = namei_GetLinkCount(fdP, (Inode) 0, 1)) < 0) {
681                 FDH_REALLYCLOSE(fdP);
682                 IH_RELEASE(tmp);
683                 return -1;
684             }
685
686             count--;
687             if (namei_SetLinkCount(fdP, (Inode) 0, count < 0 ? 0 : count, 1) <
688                 0) {
689                 FDH_REALLYCLOSE(fdP);
690                 IH_RELEASE(tmp);
691                 return -1;
692             }
693
694             if (count > 0) {
695                 FDH_REALLYCLOSE(fdP);
696                 IH_RELEASE(tmp);
697                 return 0;
698             }
699         }
700
701         namei_HandleToName(&name, tmp);
702         if ((code = unlink(name.n_path)) == 0) {
703             if (type == VI_LINKTABLE) {
704                 /* Try to remove directory. If it fails, that's ok.
705                  * Salvage will clean up.
706                  */
707                 (void)namei_RemoveDataDirectories(&name);
708             }
709         }
710         FDH_REALLYCLOSE(fdP);
711         IH_RELEASE(tmp);
712     } else {
713         /* Get a file descriptor handle for this Inode */
714         fdP = IH_OPEN(ih);
715         if (fdP == NULL) {
716             return -1;
717         }
718
719         if ((count = namei_GetLinkCount(fdP, ino, 1)) < 0) {
720             FDH_REALLYCLOSE(fdP);
721             return -1;
722         }
723
724         count--;
725         if (count >= 0) {
726             if (namei_SetLinkCount(fdP, ino, count, 1) < 0) {
727                 FDH_REALLYCLOSE(fdP);
728                 return -1;
729             }
730         } else {
731             IHandle_t *th;
732             IH_INIT(th, ih->ih_dev, ih->ih_vid, ino);
733             Log("Warning: Lost ref on ihandle dev %d vid %d ino %" AFS_INT64_FMT "\n",
734                 th->ih_dev, th->ih_vid, (int64_t) th->ih_ino);
735             IH_RELEASE(th);
736           
737             /* If we're less than 0, someone presumably unlinked;
738                don't bother setting count to 0, but we need to drop a lock */
739             if (namei_SetLinkCount(fdP, ino, 0, 1) < 0) {
740                 FDH_REALLYCLOSE(fdP);
741                 return -1;
742             }
743         }
744         if (count == 0) {
745             IHandle_t *th;
746             IH_INIT(th, ih->ih_dev, ih->ih_vid, ino);
747
748             namei_HandleToName(&name, th);
749             IH_RELEASE(th);
750             code = unlink(name.n_path);
751         }
752         FDH_CLOSE(fdP);
753     }
754
755     return code;
756 }
757
758 int
759 namei_inc(IHandle_t * h, Inode ino, int p1)
760 {
761     int count;
762     int code = 0;
763     FdHandle_t *fdP;
764
765     if ((ino & NAMEI_INODESPECIAL) == NAMEI_INODESPECIAL) {
766         int type = (int)((ino >> NAMEI_TAGSHIFT) & NAMEI_TAGMASK);
767         if (type != VI_LINKTABLE)
768             return 0;
769         ino = (Inode) 0;
770     }
771
772     /* Get a file descriptor handle for this Inode */
773     fdP = IH_OPEN(h);
774     if (fdP == NULL) {
775         return -1;
776     }
777
778     if ((count = namei_GetLinkCount(fdP, ino, 1)) < 0)
779         code = -1;
780     else {
781         count++;
782         if (count > 7) {
783             errno = EINVAL;
784             code = -1;
785             count = 7;
786         }
787         if (namei_SetLinkCount(fdP, ino, count, 1) < 0)
788             code = -1;
789     }
790     if (code) {
791         FDH_REALLYCLOSE(fdP);
792     } else {
793         FDH_CLOSE(fdP);
794     }
795     return code;
796 }
797
798 int
799 namei_replace_file_by_hardlink(IHandle_t *hLink, IHandle_t *hTarget)
800 {
801     afs_int32 code;
802     namei_t nameLink;
803     namei_t nameTarget;
804     
805     /* Convert handle to file name. */
806     namei_HandleToName(&nameLink, hLink);
807     namei_HandleToName(&nameTarget, hTarget);
808     
809     unlink(nameLink.n_path);
810     code = link(nameTarget.n_path, nameLink.n_path);
811     return code;
812 }
813
814 int
815 namei_copy_on_write(IHandle_t *h)
816 {
817     afs_int32 fd, code = 0;
818     namei_t name;
819     FdHandle_t *fdP;
820     struct afs_stat tstat;
821     
822     namei_HandleToName(&name, h);
823     if (afs_stat(name.n_path, &tstat) < 0) 
824         return EIO;
825     if (tstat.st_nlink > 1) {                   /* do a copy on write */
826         char path[259];
827         char *buf;
828         afs_size_t size;
829         afs_int32 tlen;
830         
831         fdP = IH_OPEN(h);
832         if (!fdP)
833             return EIO;
834         strcpy(&path, name.n_path);
835         strcat(&path, "-tmp");
836         fd = afs_open(path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0);
837         if (fd < 0) {
838             FDH_CLOSE(fdP);
839             return EIO;
840         }
841         buf = malloc(8192);
842         if (!buf) {
843             close(fd);
844             unlink(path);
845             FDH_CLOSE(fdP);
846             return ENOMEM;
847         }
848         size = tstat.st_size;
849         FDH_SEEK(fdP, 0, 0);
850         while (size) {
851             tlen = size > 8192 ? 8192 : size;
852             if (FDH_READ(fdP, buf, tlen) != tlen) 
853                 break;
854             if (write(fd, buf, tlen) != tlen) 
855                 break;
856             size -= tlen;
857         }
858         close(fd);
859         FDH_REALLYCLOSE(fdP);
860         free(buf);
861         if (size)
862             code = EIO;
863         else {
864             unlink(name.n_path);
865             code = rename(path, name.n_path);
866         }
867     }
868     return code;
869 }
870
871 /************************************************************************
872  * File Name Structure
873  ************************************************************************
874  *
875  * Each AFS file needs a unique name and it needs to be findable with
876  * minimal lookup time. Note that the constraint on the number of files and
877  * directories in a volume is the size of the vnode index files and the
878  * max file size AFS supports (for internal files) of 2^31. Since a record
879  * in the small vnode index file is 64 bytes long, we can have at most
880  * (2^31)/64 or 33554432 files. A record in the large index file is
881  * 256 bytes long, giving a maximum of (2^31)/256 = 8388608 directories.
882  * Another layout parameter is that there is roughly a 16 to 1 ratio between
883  * the number of files and the number of directories.
884  *
885  * Using this information we can see that a layout of 256 directories, each
886  * with 512 subdirectories and each of those having 512 files gives us
887  * 256*512*512 = 67108864 AFS files and directories. 
888  *
889  * The volume, vnode, uniquifier and data version, as well as the tag
890  * are required, either for finding the file or for salvaging. It's best to 
891  * restrict the name to something that can be mapped into 64 bits so the
892  * "Inode" is easily comparable (using "==") to other "Inodes". The tag
893  * is used to distinguish between different versions of the same file
894  * which are currently in the RW and clones of a volume. See "Link Table
895  * Organization" below for more information on the tag. The tag is 
896  * required in the name of the file to ensure a unique name. 
897  *
898  * We can store data in the uid, gid and mode bits of the files, provided
899  * the directories have root only access. This gives us 15 bits for each
900  * of uid and gid (GNU chown considers 65535 to mean "don't change").
901  * There are 9 available mode bits. Adn we need to store a total of 
902  * 32 (volume id) + 26 (vnode) + 32 (uniquifier) + 32 (data-version) + 3 (tag)
903  * or 131 bits somewhere. 
904  *
905  * The format of a file name for a regular file is:
906  * /vicepX/AFSIDat/V1/V2/AA/BB/<tag><uniq><vno>
907  * V1 - low 8 bits of RW volume id
908  * V2 - all bits of RW volume id
909  * AA - high 8 bits of vnode number.
910  * BB - next 9 bits of vnode number.
911  * <tag><uniq><vno> - file name
912  *
913  * Volume special files are stored in a separate directory:
914  * /vicepX/AFSIDat/V1/V2/special/<tag><uniq><vno>
915  *
916  *
917  * The vnode is hashed into the directory using the high bits of the
918  * vnode number. This is so that consecutively created vnodes are in
919  * roughly the same area on the disk. This will at least be optimal if
920  * the user is creating many files in the same AFS directory. The name
921  * should be formed so that the leading characters are different as quickly
922  * as possible, leading to faster discards of incorrect matches in the
923  * lookup code.
924  * 
925  */
926
927
928 /************************************************************************
929  *  Link Table Organization
930  ************************************************************************
931  *
932  * The link table volume special file is used to hold the link counts that
933  * are held in the inodes in inode based AFS vice filesystems. For user
934  * space access, the link counts are being kept in a separate
935  * volume special file. The file begins with the usual version stamp
936  * information and is then followed by one row per vnode number. vnode 0
937  * is used to hold the link count of the link table itself. That is because
938  * the same link table is shared among all the volumes of the volume group
939  * and is deleted only when the last volume of a volume group is deleted.
940  *
941  * Within each row, the columns are 3 bits wide. They can each hold a 0 based
942  * link count from 0 through 7. Each colume represents a unique instance of
943  * that vnode. Say we have a file shared between the RW and a RO and a
944  * different version of the file (or a different uniquifer) for the BU volume.
945  * Then one column would be holding the link count of 2 for the RW and RO
946  * and a different column would hold the link count of 1 for the BU volume.
947  * Note that we allow only 5 volumes per file, giving 15 bits used in the
948  * short.
949  */
950 #define LINKTABLE_WIDTH 2
951 #define LINKTABLE_SHIFT 1       /* log 2 = 1 */
952
953 static void
954 namei_GetLCOffsetAndIndexFromIno(Inode ino, afs_foff_t * offset, int *index)
955 {
956     int toff = (int)(ino & NAMEI_VNODEMASK);
957     int tindex = (int)((ino >> NAMEI_TAGSHIFT) & NAMEI_TAGMASK);
958
959     *offset = (afs_foff_t) ((toff << LINKTABLE_SHIFT) + 8);     /* * 2 + sizeof stamp */
960     *index = (tindex << 1) + tindex;
961 }
962
963
964 /* namei_GetLinkCount
965  * If lockit is set, lock the file and leave it locked upon a successful
966  * return.
967  */
968 static int
969 namei_GetLinkCount2(FdHandle_t * h, Inode ino, int lockit, int fixup, int nowrite)
970 {
971     unsigned short row = 0;
972     afs_foff_t offset;
973     ssize_t rc;
974     int index;
975
976     /* there's no linktable yet. the salvager will create one later */
977     if (h->fd_fd == -1 && fixup)
978        return 1;
979     namei_GetLCOffsetAndIndexFromIno(ino, &offset, &index);
980
981     if (lockit) {
982         if (flock(h->fd_fd, LOCK_EX) < 0)
983             return -1;
984     }
985
986     if (afs_lseek(h->fd_fd, offset, SEEK_SET) == -1)
987         goto bad_getLinkByte;
988
989     rc = read(h->fd_fd, (char *)&row, sizeof(row));
990     if ((rc == 0 || !((row >> index) & NAMEI_TAGMASK)) && fixup && nowrite)
991         return 1;
992     if (rc == 0 && fixup) {
993         struct stat st;
994         if (fstat(h->fd_fd, &st) || st.st_size >= offset+sizeof(row))
995            goto bad_getLinkByte;
996         FDH_TRUNC(h, offset+sizeof(row));
997         row = 1 << index;
998         rc = write(h->fd_fd, (char *)&row, sizeof(row));
999     }
1000     if (rc != sizeof(row)) {
1001         goto bad_getLinkByte;
1002     }
1003
1004     if (fixup && !((row >> index) & NAMEI_TAGMASK)) {
1005         row |= 1<<index;
1006         if (afs_lseek(h->fd_fd, offset, SEEK_SET) == -1)
1007             goto bad_getLinkByte;
1008         rc = write(h->fd_fd, (char *)&row, sizeof(row));
1009         if (rc != sizeof(row))
1010             goto bad_getLinkByte;
1011     }
1012  
1013     return (int)((row >> index) & NAMEI_TAGMASK);
1014
1015   bad_getLinkByte:
1016     if (lockit)
1017         flock(h->fd_fd, LOCK_UN);
1018     return -1;
1019 }
1020
1021 int
1022 namei_GetLinkCount(FdHandle_t * h, Inode ino, int lockit) 
1023 {
1024     return namei_GetLinkCount2(h, ino, lockit, 0, 1);
1025 }
1026
1027 /* Return a free column index for this vnode. */
1028 static int
1029 GetFreeTag(IHandle_t * ih, int vno)
1030 {
1031     FdHandle_t *fdP;
1032     afs_foff_t offset;
1033     int col;
1034     int coldata;
1035     short row;
1036     int code;
1037
1038
1039     fdP = IH_OPEN(ih);
1040     if (fdP == NULL)
1041         return -1;
1042
1043     /* Only one manipulates at a time. */
1044     if (flock(fdP->fd_fd, LOCK_EX) < 0) {
1045         FDH_REALLYCLOSE(fdP);
1046         return -1;
1047     }
1048
1049     offset = (vno << LINKTABLE_SHIFT) + 8;      /* * 2 + sizeof stamp */
1050     if (afs_lseek(fdP->fd_fd, offset, SEEK_SET) == -1) {
1051         goto badGetFreeTag;
1052     }
1053
1054     code = read(fdP->fd_fd, (char *)&row, sizeof(row));
1055     if (code != sizeof(row)) {
1056         if (code != 0)
1057             goto badGetFreeTag;
1058         row = 0;
1059     }
1060
1061     /* Now find a free column in this row and claim it. */
1062     for (col = 0; col < NAMEI_MAXVOLS; col++) {
1063         coldata = 7 << (col * 3);
1064         if ((row & coldata) == 0)
1065             break;
1066     }
1067     if (col >= NAMEI_MAXVOLS) {
1068         errno = ENOSPC;
1069         goto badGetFreeTag;
1070     }
1071
1072     coldata = 1 << (col * 3);
1073     row |= coldata;
1074
1075     if (afs_lseek(fdP->fd_fd, offset, SEEK_SET) == -1) {
1076         goto badGetFreeTag;
1077     }
1078     if (write(fdP->fd_fd, (char *)&row, sizeof(row)) != sizeof(row)) {
1079         goto badGetFreeTag;
1080     }
1081     FDH_SYNC(fdP);
1082     flock(fdP->fd_fd, LOCK_UN);
1083     FDH_REALLYCLOSE(fdP);
1084     return col;;
1085
1086   badGetFreeTag:
1087     flock(fdP->fd_fd, LOCK_UN);
1088     FDH_REALLYCLOSE(fdP);
1089     return -1;
1090 }
1091
1092
1093
1094 /* namei_SetLinkCount
1095  * If locked is set, assume file is locked. Otherwise, lock file before
1096  * proceeding to modify it.
1097  */
1098 int
1099 namei_SetLinkCount(FdHandle_t * fdP, Inode ino, int count, int locked)
1100 {
1101     afs_foff_t offset;
1102     int index;
1103     unsigned short row;
1104     int junk;
1105     int code = -1;
1106
1107     namei_GetLCOffsetAndIndexFromIno(ino, &offset, &index);
1108
1109     if (!locked) {
1110         if (flock(fdP->fd_fd, LOCK_EX) < 0) {
1111             return -1;
1112         }
1113     }
1114     if (afs_lseek(fdP->fd_fd, offset, SEEK_SET) == -1) {
1115         errno = EBADF;
1116         goto bad_SetLinkCount;
1117     }
1118
1119
1120     code = read(fdP->fd_fd, (char *)&row, sizeof(row));
1121     if (code != sizeof(row)) {
1122         if (code != 0) {
1123             errno = EBADF;
1124             goto bad_SetLinkCount;
1125         }
1126         row = 0;
1127     }
1128
1129     junk = 7 << index;
1130     count <<= index;
1131     row &= (unsigned short)~junk;
1132     row |= (unsigned short)count;
1133
1134     if (afs_lseek(fdP->fd_fd, offset, SEEK_SET) == -1) {
1135         errno = EBADF;
1136         goto bad_SetLinkCount;
1137     }
1138
1139     if (write(fdP->fd_fd, (char *)&row, sizeof(short)) != sizeof(short)) {
1140         errno = EBADF;
1141         goto bad_SetLinkCount;
1142     }
1143     FDH_SYNC(fdP);
1144
1145     code = 0;
1146
1147
1148   bad_SetLinkCount:
1149     flock(fdP->fd_fd, LOCK_UN);
1150
1151     return code;
1152 }
1153
1154
1155 /* ListViceInodes - write inode data to a results file. */
1156 static int DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
1157                        int volid);
1158 static int DecodeVolumeName(char *name, int *vid);
1159 static int namei_ListAFSSubDirs(IHandle_t * dirIH,
1160                                 int (*write_fun) (FILE *,
1161                                                   struct ViceInodeInfo *,
1162                                                   char *, char *), FILE * fp,
1163                                 int (*judgeFun) (struct ViceInodeInfo *,
1164                                                  afs_uint32 vid, void *),
1165                                 afs_uint32 singleVolumeNumber, void *rock);
1166
1167
1168 /* WriteInodeInfo
1169  *
1170  * Write the inode data to the results file. 
1171  *
1172  * Returns -2 on error, 0 on success.
1173  *
1174  * This is written as a callback simply so that other listing routines
1175  * can use the same inode reading code.
1176  */
1177 static int
1178 WriteInodeInfo(FILE * fp, struct ViceInodeInfo *info, char *dir, char *name)
1179 {
1180     int n;
1181     n = fwrite(info, sizeof(*info), 1, fp);
1182     return (n == 1) ? 0 : -2;
1183 }
1184
1185
1186 int mode_errors;                /* Number of errors found in mode bits on directories. */
1187 void
1188 VerifyDirPerms(char *path)
1189 {
1190     struct afs_stat status;
1191
1192     if (afs_stat(path, &status) < 0) {
1193         Log("Unable to stat %s. Please manually verify mode bits for this"
1194             " directory\n", path);
1195     } else {
1196         if (((status.st_mode & 0777) != 0700) || (status.st_uid != 0))
1197             mode_errors++;
1198     }
1199 }
1200
1201 /* ListViceInodes
1202  * Fill the results file with the requested inode information.
1203  *
1204  * Return values:
1205  *  0 - success
1206  * -1 - complete failure, salvage should terminate.
1207  * -2 - not enough space on partition, salvager has error message for this.
1208  *
1209  * This code optimizes single volume salvages by just looking at that one
1210  * volume's directory. 
1211  *
1212  * If the resultFile is NULL, then don't call the write routine.
1213  */
1214 int
1215 ListViceInodes(char *devname, char *mountedOn, char *resultFile,
1216                int (*judgeInode) (struct ViceInodeInfo * info, afs_uint32 vid, void *rock),
1217                afs_uint32 singleVolumeNumber, int *forcep, int forceR, char *wpath, 
1218                void *rock)
1219 {
1220     FILE *fp = (FILE *) - 1;
1221     int ninodes;
1222     struct afs_stat status;
1223
1224     *forcep = 0; /* no need to salvage until further notice */
1225
1226     if (resultFile) {
1227         fp = afs_fopen(resultFile, "w");
1228         if (!fp) {
1229             Log("Unable to create inode description file %s\n", resultFile);
1230             return -1;
1231         }
1232     }
1233
1234     /* Verify protections on directories. */
1235     mode_errors = 0;
1236     VerifyDirPerms(mountedOn);
1237
1238     ninodes =
1239         namei_ListAFSFiles(mountedOn, WriteInodeInfo, fp, judgeInode,
1240                            singleVolumeNumber, rock);
1241
1242     if (!resultFile)
1243         return ninodes;
1244
1245     if (ninodes < 0) {
1246         fclose(fp);
1247         return ninodes;
1248     }
1249
1250     if (fflush(fp) == EOF) {
1251         Log("Unable to successfully flush inode file for %s\n", mountedOn);
1252         fclose(fp);
1253         return -2;
1254     }
1255     if (fsync(fileno(fp)) == -1) {
1256         Log("Unable to successfully fsync inode file for %s\n", mountedOn);
1257         fclose(fp);
1258         return -2;
1259     }
1260     if (fclose(fp) == EOF) {
1261         Log("Unable to successfully close inode file for %s\n", mountedOn);
1262         return -2;
1263     }
1264
1265     /*
1266      * Paranoia:  check that the file is really the right size
1267      */
1268     if (afs_stat(resultFile, &status) == -1) {
1269         Log("Unable to successfully stat inode file for %s\n", mountedOn);
1270         return -2;
1271     }
1272     if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
1273         Log("Wrong size (%d instead of %d) in inode file for %s\n",
1274             status.st_size, ninodes * sizeof(struct ViceInodeInfo),
1275             mountedOn);
1276         return -2;
1277     }
1278     return 0;
1279 }
1280
1281
1282 /* namei_ListAFSFiles
1283  *
1284  * Collect all the matching AFS files on the drive.
1285  * If singleVolumeNumber is non-zero, just return files for that volume.
1286  *
1287  * Returns <0 on error, else number of files found to match.
1288  */
1289 int
1290 namei_ListAFSFiles(char *dev,
1291                    int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
1292                                     char *), FILE * fp,
1293                    int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *),
1294                    afs_uint32 singleVolumeNumber, void *rock)
1295 {
1296     IHandle_t ih;
1297     namei_t name;
1298     int ninodes = 0;
1299     DIR *dirp1, *dirp2;
1300     struct dirent *dp1, *dp2;
1301     char path2[512];
1302 #ifdef DELETE_ZLC
1303     static void FreeZLCList(void);
1304 #endif
1305
1306     memset((void *)&ih, 0, sizeof(IHandle_t));
1307     ih.ih_dev = volutil_GetPartitionID(dev);
1308
1309     if (singleVolumeNumber) {
1310         ih.ih_vid = singleVolumeNumber;
1311         namei_HandleToVolDir(&name, &ih);
1312         ninodes =
1313             namei_ListAFSSubDirs(&ih, writeFun, fp, judgeFun,
1314                                  singleVolumeNumber, rock);
1315         if (ninodes < 0)
1316             return ninodes;
1317     } else {
1318         /* Find all volume data directories and descend through them. */
1319         namei_HandleToInodeDir(&name, &ih);
1320         ninodes = 0;
1321         dirp1 = opendir(name.n_path);
1322         if (!dirp1)
1323             return 0;
1324         while ((dp1 = readdir(dirp1))) {
1325             if (*dp1->d_name == '.')
1326                 continue;
1327             (void)strcpy(path2, name.n_path);
1328             (void)strcat(path2, "/");
1329             (void)strcat(path2, dp1->d_name);
1330             dirp2 = opendir(path2);
1331             if (dirp2) {
1332                 while ((dp2 = readdir(dirp2))) {
1333                     if (*dp2->d_name == '.')
1334                         continue;
1335                     if (!DecodeVolumeName(dp2->d_name, &ih.ih_vid)) {
1336                         ninodes +=
1337                             namei_ListAFSSubDirs(&ih, writeFun, fp, judgeFun,
1338                                                  0, rock);
1339                     }
1340                 }
1341                 closedir(dirp2);
1342             }
1343         }
1344         closedir(dirp1);
1345     }
1346 #ifdef DELETE_ZLC
1347     FreeZLCList();
1348 #endif
1349     return ninodes;
1350 }
1351
1352
1353
1354 /* namei_ListAFSSubDirs
1355  *
1356  *
1357  * Return values:
1358  * < 0 - an error
1359  * > = 0 - number of AFS files found.
1360  */
1361 static int
1362 namei_ListAFSSubDirs(IHandle_t * dirIH,
1363                      int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
1364                                       char *), FILE * fp,
1365                      int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *),
1366                      afs_uint32 singleVolumeNumber, void *rock)
1367 {
1368     IHandle_t myIH = *dirIH;
1369     namei_t name;
1370     char path1[512], path2[512], path3[512];
1371     DIR *dirp1, *dirp2, *dirp3;
1372     struct dirent *dp1, *dp2, *dp3;
1373     struct ViceInodeInfo info;
1374     FdHandle_t linkHandle;
1375     int ninodes = 0;
1376 #ifdef DELETE_ZLC
1377     int i;
1378     static void AddToZLCDeleteList(char dir, char *name);
1379     static void DeleteZLCFiles(char *path);
1380 #endif
1381
1382     namei_HandleToVolDir(&name, &myIH);
1383     (void)strcpy(path1, name.n_path);
1384
1385     /* Do the directory containing the special files first to pick up link
1386      * counts.
1387      */
1388     (void)strcat(path1, "/");
1389     (void)strcat(path1, NAMEI_SPECDIR);
1390
1391     linkHandle.fd_fd = -1;
1392     dirp1 = opendir(path1);
1393     if (dirp1) {
1394         while ((dp1 = readdir(dirp1))) {
1395             if (*dp1->d_name == '.')
1396                 continue;
1397             if (DecodeInode(path1, dp1->d_name, &info, myIH.ih_vid) < 0)
1398                 continue;
1399             if (info.u.param[2] != VI_LINKTABLE) {
1400                 info.linkCount = 1;
1401             } else {
1402                 /* Open this handle */
1403                 (void)afs_snprintf(path2, sizeof path2, "%s/%s", path1,
1404                                    dp1->d_name);
1405                 linkHandle.fd_fd = afs_open(path2, Testing ? O_RDONLY : O_RDWR, 0666);
1406                 info.linkCount =
1407                     namei_GetLinkCount2(&linkHandle, (Inode) 0, 1, 1, Testing);
1408             }
1409             if (judgeFun && !(*judgeFun) (&info, singleVolumeNumber, rock))
1410                 continue;
1411
1412             if ((*writeFun) (fp, &info, path1, dp1->d_name) < 0) {
1413                 if (linkHandle.fd_fd >= 0)
1414                     close(linkHandle.fd_fd);
1415                 closedir(dirp1);
1416                 return -1;
1417             }
1418             ninodes++;
1419         }
1420         closedir(dirp1);
1421     }
1422
1423     /* Now run through all the other subdirs */
1424     namei_HandleToVolDir(&name, &myIH);
1425     (void)strcpy(path1, name.n_path);
1426
1427     dirp1 = opendir(path1);
1428     if (dirp1) {
1429         while ((dp1 = readdir(dirp1))) {
1430             if (*dp1->d_name == '.')
1431                 continue;
1432             if (!strcmp(dp1->d_name, NAMEI_SPECDIR))
1433                 continue;
1434
1435             /* Now we've got a next level subdir. */
1436             (void)strcpy(path2, path1);
1437             (void)strcat(path2, "/");
1438             (void)strcat(path2, dp1->d_name);
1439             dirp2 = opendir(path2);
1440             if (dirp2) {
1441                 while ((dp2 = readdir(dirp2))) {
1442                     if (*dp2->d_name == '.')
1443                         continue;
1444
1445                     /* Now we've got to the actual data */
1446                     (void)strcpy(path3, path2);
1447                     (void)strcat(path3, "/");
1448                     (void)strcat(path3, dp2->d_name);
1449                     dirp3 = opendir(path3);
1450                     if (dirp3) {
1451                         while ((dp3 = readdir(dirp3))) {
1452                             if (*dp3->d_name == '.')
1453                                 continue;
1454                             if (DecodeInode
1455                                 (path3, dp3->d_name, &info, myIH.ih_vid) < 0)
1456                                 continue;
1457                             info.linkCount =
1458                                 namei_GetLinkCount2(&linkHandle,
1459                                                    info.inodeNumber, 1, 1, Testing);
1460                             if (info.linkCount == 0) {
1461 #ifdef DELETE_ZLC
1462                                 Log("Found 0 link count file %s/%s, deleting it.\n", path3, dp3->d_name);
1463                                 AddToZLCDeleteList((char)i, dp3->d_name);
1464 #else
1465                                 Log("Found 0 link count file %s/%s.\n", path3,
1466                                     dp3->d_name);
1467 #endif
1468                                 continue;
1469                             }
1470                             if (judgeFun
1471                                 && !(*judgeFun) (&info, singleVolumeNumber, rock))
1472                                 continue;
1473
1474                             if ((*writeFun) (fp, &info, path3, dp3->d_name) <
1475                                 0) {
1476                                 close(linkHandle.fd_fd);
1477                                 closedir(dirp3);
1478                                 closedir(dirp2);
1479                                 closedir(dirp1);
1480                                 return -1;
1481                             }
1482                             ninodes++;
1483                         }
1484                         closedir(dirp3);
1485                     }
1486                 }
1487                 closedir(dirp2);
1488             }
1489         }
1490         closedir(dirp1);
1491     }
1492
1493     if (linkHandle.fd_fd >= 0)
1494         close(linkHandle.fd_fd);
1495     if (!ninodes) {
1496         /* Then why does this directory exist? Blow it away. */
1497         namei_HandleToVolDir(&name, dirIH);
1498         namei_RemoveDataDirectories(&name);
1499     }
1500
1501     return ninodes;
1502 }
1503
1504 static int
1505 DecodeVolumeName(char *name, int *vid)
1506 {
1507     if (strlen(name) <= 2)
1508         return -1;
1509     *vid = (int)flipbase64_to_int64(name);
1510     return 0;
1511 }
1512
1513
1514 /* DecodeInode
1515  *
1516  * Get the inode number from the name.
1517  * Get
1518  */
1519 static int
1520 DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info, int volid)
1521 {
1522     char fpath[512];
1523     struct afs_stat status;
1524     int parm, tag;
1525     lb64_string_t check;
1526
1527     (void)strcpy(fpath, dpath);
1528     (void)strcat(fpath, "/");
1529     (void)strcat(fpath, name);
1530
1531     if (afs_stat(fpath, &status) < 0) {
1532         return -1;
1533     }
1534
1535     info->byteCount = status.st_size;
1536     info->inodeNumber = (Inode) flipbase64_to_int64(name);
1537
1538     int64_to_flipbase64(check, info->inodeNumber);
1539     if (strcmp(name, check))
1540         return -1;
1541     
1542     GetOGMFromStat(&status, &parm, &tag);
1543     if ((info->inodeNumber & NAMEI_INODESPECIAL) == NAMEI_INODESPECIAL) {
1544         /* p1 - vid, p2 - -1, p3 - type, p4 - rwvid */
1545         info->u.param[0] = parm;
1546         info->u.param[1] = -1;
1547         info->u.param[2] = tag;
1548         info->u.param[3] = volid;
1549     } else {
1550         /* p1 - vid, p2 - vno, p3 - uniq, p4 - dv */
1551         info->u.param[0] = volid;
1552         info->u.param[1] = (int)(info->inodeNumber & NAMEI_VNODEMASK);
1553         info->u.param[2] = (int)((info->inodeNumber >> NAMEI_UNIQSHIFT)
1554                                  & (Inode) NAMEI_UNIQMASK);
1555         info->u.param[3] = parm;
1556     }
1557     return 0;
1558 }
1559
1560 /*
1561  * Convert the VolumeInfo file from RO to RW
1562  * this routine is called by namei_convertROtoRWvolume()
1563  */
1564
1565 static afs_int32
1566 convertVolumeInfo(int fdr, int fdw, afs_uint32 vid)
1567 {
1568     struct VolumeDiskData vd;
1569     char *p;
1570
1571     if (read(fdr, &vd, sizeof(struct VolumeDiskData)) !=
1572         sizeof(struct VolumeDiskData)) {
1573         Log("1 convertVolumeInfo: read failed for %lu with code %d\n", vid,
1574             errno);
1575         return -1;
1576     }
1577     vd.restoredFromId = vd.id;  /* remember the RO volume here */
1578     vd.cloneId = vd.id;
1579     vd.id = vd.parentId;
1580     vd.type = RWVOL;
1581     vd.dontSalvage = 0;
1582     vd.uniquifier += 5000;      /* just in case there are still file copies from
1583                                  * the old RW volume around */
1584     p = strrchr(vd.name, '.');
1585     if (p && !strcmp(p, ".readonly")) {
1586         memset(p, 0, 9);
1587     }
1588     if (write(fdw, &vd, sizeof(struct VolumeDiskData)) !=
1589         sizeof(struct VolumeDiskData)) {
1590         Log("1 convertVolumeInfo: write failed for %lu with code %d\n", vid,
1591             errno);
1592         return -1;
1593     }
1594     return 0;
1595 }
1596
1597 /*
1598  * Convert a RO-volume into a RW-volume
1599  *
1600  * This function allows to recover very fast from the loss of a partition
1601  * from RO-copies if all RO-Copies exist on another partition.
1602  * Then these RO-volumes can be made to the new RW-volumes.
1603  * Backup of RW-volumes then consists in "vos release".
1604  *
1605  * We must make sure in this partition exists only the RO-volume which
1606  * is typical for remote replicas.
1607  *
1608  * Then the linktable is already ok,
1609  *      the vnode files need to be renamed
1610  *      the volinfo file needs to be replaced by another one with
1611  *                      slightly different contents and new name.
1612  * The volume header file of the RO-volume in the /vicep<x> directory
1613  * is destroyed by this call. A new header file for the RW-volume must
1614  * be created after return from this routine.
1615  */
1616
1617 int
1618 namei_ConvertROtoRWvolume(char *pname, afs_uint32 volumeId)
1619 {
1620 #ifdef FSSYNC_BUILD_CLIENT
1621     namei_t n;
1622     char dir_name[512], oldpath[512], newpath[512];
1623     char smallName[64];
1624     char largeName[64];
1625     char infoName[64];
1626     IHandle_t t_ih;
1627     IHandle_t *ih;
1628     char infoSeen = 0;
1629     char smallSeen = 0;
1630     char largeSeen = 0;
1631     char linkSeen = 0;
1632     int code, fd, fd2;
1633     char *p;
1634     DIR *dirp;
1635     Inode ino;
1636     struct dirent *dp;
1637     struct DiskPartition64 *partP;
1638     struct ViceInodeInfo info;
1639     struct VolumeDiskHeader h;
1640     char headername[16];
1641     afs_int32 error = 0;
1642
1643     (void)afs_snprintf(headername, sizeof headername, VFORMAT, afs_cast_uint32(volumeId));
1644     (void)afs_snprintf(oldpath, sizeof oldpath, "%s/%s", pname, headername);
1645     fd = open(oldpath, O_RDONLY);
1646     if (fd < 0) {
1647         Log("1 namei_ConvertROtoRWvolume: Couldn't open header for RO-volume %lu.\n", volumeId);
1648         return ENOENT;
1649     }
1650     if (read(fd, &h, sizeof(h)) != sizeof(h)) {
1651         Log("1 namei_ConvertROtoRWvolume: Couldn't read header for RO-volume %lu.\n", volumeId);
1652         close(fd);
1653         return EIO;
1654     }
1655     close(fd);
1656     FSYNC_VolOp(volumeId, pname, FSYNC_VOL_BREAKCBKS, 0, NULL);
1657
1658     for (partP = DiskPartitionList; partP && strcmp(partP->name, pname);
1659          partP = partP->next);
1660     if (!partP) {
1661         Log("1 namei_ConvertROtoRWvolume: Couldn't find DiskPartition for %s\n", pname);
1662         return EIO;
1663     }
1664     ino = namei_MakeSpecIno(h.parent, VI_LINKTABLE);
1665     IH_INIT(ih, partP->device, h.parent, ino);
1666
1667     namei_HandleToName(&n, ih);
1668     strcpy(dir_name, n.n_path);
1669     p = strrchr(dir_name, '/');
1670     *p = 0;
1671     dirp = opendir(dir_name);
1672     if (!dirp) {
1673         Log("1 namei_ConvertROtoRWvolume: Could not opendir(%s)\n", dir_name);
1674         return EIO;
1675     }
1676
1677     while ((dp = readdir(dirp))) {
1678         /* struct ViceInodeInfo info; */
1679
1680         if (*dp->d_name == '.')
1681             continue;
1682         if (DecodeInode(dir_name, dp->d_name, &info, ih->ih_vid) < 0) {
1683             Log("1 namei_ConvertROtoRWvolume: DecodeInode failed for %s/%s\n",
1684                 dir_name, dp->d_name);
1685             closedir(dirp);
1686             return -1;
1687         }
1688         if (info.u.param[1] != -1) {
1689             Log("1 namei_ConvertROtoRWvolume: found other than volume special file %s/%s\n", dir_name, dp->d_name);
1690             closedir(dirp);
1691             return -1;
1692         }
1693         if (info.u.param[0] != volumeId) {
1694             if (info.u.param[0] == ih->ih_vid) {
1695                 if (info.u.param[2] == VI_LINKTABLE) {  /* link table */
1696                     linkSeen = 1;
1697                     continue;
1698                 }
1699             }
1700             Log("1 namei_ConvertROtoRWvolume: found special file %s/%s for volume %lu\n", dir_name, dp->d_name, info.u.param[0]);
1701             closedir(dirp);
1702             return VVOLEXISTS;
1703         }
1704         if (info.u.param[2] == VI_VOLINFO) {    /* volume info file */
1705             strcpy(infoName, dp->d_name);
1706             infoSeen = 1;
1707         } else if (info.u.param[2] == VI_SMALLINDEX) {  /* small vnodes file */
1708             strcpy(smallName, dp->d_name);
1709             smallSeen = 1;
1710         } else if (info.u.param[2] == VI_LARGEINDEX) {  /* large vnodes file */
1711             strcpy(largeName, dp->d_name);
1712             largeSeen = 1;
1713         } else {
1714             closedir(dirp);
1715             Log("1 namei_ConvertROtoRWvolume: unknown type %d of special file found : %s/%s\n", info.u.param[2], dir_name, dp->d_name);
1716             return -1;
1717         }
1718     }
1719     closedir(dirp);
1720
1721     if (!infoSeen || !smallSeen || !largeSeen || !linkSeen) {
1722         Log("1 namei_ConvertROtoRWvolume: not all special files found in %s\n", dir_name);
1723         return -1;
1724     }
1725
1726     /*
1727      * If we come here then there was only a RO-volume and we can safely
1728      * proceed.
1729      */
1730
1731     memset(&t_ih, 0, sizeof(t_ih));
1732     t_ih.ih_dev = ih->ih_dev;
1733     t_ih.ih_vid = ih->ih_vid;
1734
1735     (void)afs_snprintf(oldpath, sizeof oldpath, "%s/%s", dir_name, infoName);
1736     fd = afs_open(oldpath, O_RDWR, 0);
1737     if (fd < 0) {
1738         Log("1 namei_ConvertROtoRWvolume: could not open RO info file: %s\n",
1739             oldpath);
1740         return -1;
1741     }
1742     t_ih.ih_ino = namei_MakeSpecIno(ih->ih_vid, VI_VOLINFO);
1743     namei_HandleToName(&n, &t_ih);
1744     fd2 = afs_open(n.n_path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0);
1745     if (fd2 < 0) {
1746         Log("1 namei_ConvertROtoRWvolume: could not create RW info file: %s\n", n.n_path);
1747         close(fd);
1748         return -1;
1749     }
1750     code = convertVolumeInfo(fd, fd2, ih->ih_vid);
1751     close(fd);
1752     if (code) {
1753         close(fd2);
1754         unlink(n.n_path);
1755         return -1;
1756     }
1757     SetOGM(fd2, ih->ih_vid, 1);
1758     close(fd2);
1759
1760     t_ih.ih_ino = namei_MakeSpecIno(ih->ih_vid, VI_SMALLINDEX);
1761     namei_HandleToName(&n, &t_ih);
1762     (void)afs_snprintf(newpath, sizeof newpath, "%s/%s", dir_name, smallName);
1763     fd = afs_open(newpath, O_RDWR, 0);
1764     if (fd < 0) {
1765         Log("1 namei_ConvertROtoRWvolume: could not open SmallIndex file: %s\n", newpath);
1766         return -1;
1767     }
1768     SetOGM(fd, ih->ih_vid, 2);
1769     close(fd);
1770     link(newpath, n.n_path);
1771     unlink(newpath);
1772
1773     t_ih.ih_ino = namei_MakeSpecIno(ih->ih_vid, VI_LARGEINDEX);
1774     namei_HandleToName(&n, &t_ih);
1775     (void)afs_snprintf(newpath, sizeof newpath, "%s/%s", dir_name, largeName);
1776     fd = afs_open(newpath, O_RDWR, 0);
1777     if (fd < 0) {
1778         Log("1 namei_ConvertROtoRWvolume: could not open LargeIndex file: %s\n", newpath);
1779         return -1;
1780     }
1781     SetOGM(fd, ih->ih_vid, 3);
1782     close(fd);
1783     link(newpath, n.n_path);
1784     unlink(newpath);
1785
1786     unlink(oldpath);
1787
1788     h.id = h.parent;
1789     h.volumeInfo_hi = h.id;
1790     h.smallVnodeIndex_hi = h.id;
1791     h.largeVnodeIndex_hi = h.id;
1792     h.linkTable_hi = h.id;
1793     (void)afs_snprintf(headername, sizeof headername, VFORMAT, afs_cast_uint32(h.id));
1794     (void)afs_snprintf(newpath, sizeof newpath, "%s/%s", pname, headername);
1795     fd = open(newpath, O_CREAT | O_EXCL | O_RDWR, 0644);
1796     if (fd < 0) {
1797         Log("1 namei_ConvertROtoRWvolume: Couldn't create header for RW-volume %lu.\n", h.id);
1798         return EIO;
1799     }
1800     if (write(fd, &h, sizeof(h)) != sizeof(h)) {
1801         Log("1 namei_ConvertROtoRWvolume: Couldn't write header for RW-volume\
1802  %lu.\n", h.id);
1803         close(fd);
1804         return EIO;
1805     }
1806     close(fd);
1807     if (unlink(oldpath) < 0) {
1808         Log("1 namei_ConvertROtoRWvolume: Couldn't unlink RO header, error = %d\n", error);
1809     }
1810     FSYNC_VolOp(volumeId, pname, FSYNC_VOL_DONE, 0, NULL);
1811     FSYNC_VolOp(h.id, pname, FSYNC_VOL_ON, 0, NULL);
1812 #endif
1813     return 0;
1814 }
1815
1816 /* PrintInode
1817  *
1818  * returns a static string used to print either 32 or 64 bit inode numbers.
1819  */
1820 char *
1821 PrintInode(char *s, Inode ino)
1822 {
1823     static afs_ino_str_t result;
1824     if (!s)
1825         s = result;
1826
1827     (void)afs_snprintf(s, sizeof(afs_ino_str_t), "%llu", (afs_uintmax_t) ino);
1828
1829     return s;
1830 }
1831
1832
1833 #ifdef DELETE_ZLC
1834 /* Routines to facilitate removing zero link count files. */
1835 #define MAX_ZLC_NAMES 32
1836 #define MAX_ZLC_NAMELEN 16
1837 typedef struct zlcList_s {
1838     struct zlcList_s *zlc_next;
1839     int zlc_n;
1840     char zlc_names[MAX_ZLC_NAMES][MAX_ZLC_NAMELEN];
1841 } zlcList_t;
1842
1843 static zlcList_t *zlcAnchor = NULL;
1844 static zlcList_t *zlcCur = NULL;
1845
1846 static void
1847 AddToZLCDeleteList(char dir, char *name)
1848 {
1849     assert(strlen(name) <= MAX_ZLC_NAMELEN - 3);
1850
1851     if (!zlcCur || zlcCur->zlc_n >= MAX_ZLC_NAMES) {
1852         if (zlcCur && zlcCur->zlc_next)
1853             zlcCur = zlcCur->zlc_next;
1854         else {
1855             zlcList_t *tmp = (zlcList_t *) malloc(sizeof(zlcList_t));
1856             if (!tmp)
1857                 return;
1858             if (!zlcAnchor) {
1859                 zlcAnchor = tmp;
1860             } else {
1861                 zlcCur->zlc_next = tmp;
1862             }
1863             zlcCur = tmp;
1864             zlcCur->zlc_n = 0;
1865             zlcCur->zlc_next = NULL;
1866         }
1867     }
1868
1869     (void)sprintf(zlcCur->zlc_names[zlcCur->zlc_n], "%c\\%s", dir, name);
1870     zlcCur->zlc_n++;
1871 }
1872
1873 static void
1874 DeleteZLCFiles(char *path)
1875 {
1876     zlcList_t *z;
1877     int i;
1878     char fname[1024];
1879
1880     for (z = zlcAnchor; z; z = z->zlc_next) {
1881         for (i = 0; i < z->zlc_n; i++) {
1882             (void)sprintf(fname, "%s\\%s", path, z->zlc_names[i]);
1883             if (namei_unlink(fname) < 0) {
1884                 Log("ZLC: Can't unlink %s, dos error = %d\n", fname,
1885                     GetLastError());
1886             }
1887         }
1888         z->zlc_n = 0;           /* Can reuse space. */
1889     }
1890     zlcCur = zlcAnchor;
1891 }
1892
1893 static void
1894 FreeZLCList(void)
1895 {
1896     zlcList_t *tnext;
1897     zlcList_t *i;
1898
1899     i = zlcAnchor;
1900     while (i) {
1901         tnext = i->zlc_next;
1902         free(i);
1903         i = tnext;
1904     }
1905     zlcCur = zlcAnchor = NULL;
1906 }
1907 #endif
1908
1909 #endif /* AFS_NAMEI_ENV */