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