call-bzero-in-convertvolumeinfo-with-correct-size-for-dotreadonly-20060731
[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 #if defined(AFS_SUN5_ENV) || defined(AFS_HPUX_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         memset((void *)&tfd, 0, sizeof(FdHandle_t));    /* minimalistic still, but a little cleaner */
576         tfd.fd_ih = &tmp;
577         tfd.fd_fd = fd;
578         code = namei_SetLinkCount(&tfd, (Inode) 0, 1, 0);
579     }
580
581   bad:
582     if (fd >= 0)
583         close(fd);
584
585
586     if (code || (fd < 0)) {
587         if (p2 != -1) {
588             fdP = IH_OPEN(lh);
589             if (fdP) {
590                 namei_SetLinkCount(fdP, tmp.ih_ino, 0, 0);
591                 FDH_CLOSE(fdP);
592             }
593         }
594     }
595     return (code || (fd < 0)) ? (Inode) - 1 : tmp.ih_ino;
596 }
597
598
599 /* namei_iopen */
600 int
601 namei_iopen(IHandle_t * h)
602 {
603     int fd;
604     namei_t name;
605
606     /* Convert handle to file name. */
607     namei_HandleToName(&name, h);
608     fd = afs_open(name.n_path, O_RDWR, 0666);
609     return fd;
610 }
611
612 /* Need to detect vol special file and just unlink. In those cases, the
613  * handle passed in _is_ for the inode. We only check p1 for the special
614  * files.
615  */
616 int
617 namei_dec(IHandle_t * ih, Inode ino, int p1)
618 {
619     int count = 0;
620     namei_t name;
621     int code = 0;
622     FdHandle_t *fdP;
623
624     if ((ino & NAMEI_INODESPECIAL) == NAMEI_INODESPECIAL) {
625         IHandle_t *tmp;
626         int inode_p1, tag;
627         int type = (int)((ino >> NAMEI_TAGSHIFT) & NAMEI_TAGMASK);
628
629         /* Verify this is the right file. */
630         IH_INIT(tmp, ih->ih_dev, ih->ih_vid, ino);
631
632         fdP = IH_OPEN(tmp);
633         if (fdP == NULL) {
634             IH_RELEASE(tmp);
635             errno = EINVAL;
636             return -1;
637         }
638
639         if ((GetOGM(fdP->fd_fd, &inode_p1, &tag) < 0) || (inode_p1 != p1)) {
640             FDH_REALLYCLOSE(fdP);
641             IH_RELEASE(tmp);
642             errno = EINVAL;
643             return -1;
644         }
645
646         /* If it's the link table itself, decrement the link count. */
647         if (type == VI_LINKTABLE) {
648             if ((count = namei_GetLinkCount(fdP, (Inode) 0, 1)) < 0) {
649                 FDH_REALLYCLOSE(fdP);
650                 IH_RELEASE(tmp);
651                 return -1;
652             }
653
654             count--;
655             if (namei_SetLinkCount(fdP, (Inode) 0, count < 0 ? 0 : count, 1) <
656                 0) {
657                 FDH_REALLYCLOSE(fdP);
658                 IH_RELEASE(tmp);
659                 return -1;
660             }
661
662             if (count > 0) {
663                 FDH_REALLYCLOSE(fdP);
664                 IH_RELEASE(tmp);
665                 return 0;
666             }
667         }
668
669         namei_HandleToName(&name, tmp);
670         if ((code = unlink(name.n_path)) == 0) {
671             if (type == VI_LINKTABLE) {
672                 /* Try to remove directory. If it fails, that's ok.
673                  * Salvage will clean up.
674                  */
675                 (void)namei_RemoveDataDirectories(&name);
676             }
677         }
678         FDH_REALLYCLOSE(fdP);
679         IH_RELEASE(tmp);
680     } else {
681         /* Get a file descriptor handle for this Inode */
682         fdP = IH_OPEN(ih);
683         if (fdP == NULL) {
684             return -1;
685         }
686
687         if ((count = namei_GetLinkCount(fdP, ino, 1)) < 0) {
688             FDH_REALLYCLOSE(fdP);
689             return -1;
690         }
691
692         count--;
693         if (count >= 0) {
694             if (namei_SetLinkCount(fdP, ino, count, 1) < 0) {
695                 FDH_REALLYCLOSE(fdP);
696                 return -1;
697             }
698         } else {
699             IHandle_t *th;
700             IH_INIT(th, ih->ih_dev, ih->ih_vid, ino);
701             Log("Warning: Lost ref on ihandle dev %d vid %d ino %lld\n",
702                 th->ih_dev, th->ih_vid, (int64_t) th->ih_ino);
703             IH_RELEASE(th);
704           
705             /* If we're less than 0, someone presumably unlinked;
706                don't bother setting count to 0, but we need to drop a lock */
707             if (namei_SetLinkCount(fdP, ino, 0, 1) < 0) {
708                 FDH_REALLYCLOSE(fdP);
709                 return -1;
710             }
711         }
712         if (count == 0) {
713             IHandle_t *th;
714             IH_INIT(th, ih->ih_dev, ih->ih_vid, ino);
715
716             namei_HandleToName(&name, th);
717             IH_RELEASE(th);
718             code = unlink(name.n_path);
719         }
720         FDH_CLOSE(fdP);
721     }
722
723     return code;
724 }
725
726 int
727 namei_inc(IHandle_t * h, Inode ino, int p1)
728 {
729     int count;
730     int code = 0;
731     FdHandle_t *fdP;
732
733     if ((ino & NAMEI_INODESPECIAL) == NAMEI_INODESPECIAL) {
734         int type = (int)((ino >> NAMEI_TAGSHIFT) & NAMEI_TAGMASK);
735         if (type != VI_LINKTABLE)
736             return 0;
737         ino = (Inode) 0;
738     }
739
740     /* Get a file descriptor handle for this Inode */
741     fdP = IH_OPEN(h);
742     if (fdP == NULL) {
743         return -1;
744     }
745
746     if ((count = namei_GetLinkCount(fdP, ino, 1)) < 0)
747         code = -1;
748     else {
749         count++;
750         if (count > 7) {
751             errno = EINVAL;
752             code = -1;
753             count = 7;
754         }
755         if (namei_SetLinkCount(fdP, ino, count, 1) < 0)
756             code = -1;
757     }
758     if (code) {
759         FDH_REALLYCLOSE(fdP);
760     } else {
761         FDH_CLOSE(fdP);
762     }
763     return code;
764 }
765
766 /************************************************************************
767  * File Name Structure
768  ************************************************************************
769  *
770  * Each AFS file needs a unique name and it needs to be findable with
771  * minimal lookup time. Note that the constraint on the number of files and
772  * directories in a volume is the size of the vnode index files and the
773  * max file size AFS supports (for internal files) of 2^31. Since a record
774  * in the small vnode index file is 64 bytes long, we can have at most
775  * (2^31)/64 or 33554432 files. A record in the large index file is
776  * 256 bytes long, giving a maximum of (2^31)/256 = 8388608 directories.
777  * Another layout parameter is that there is roughly a 16 to 1 ratio between
778  * the number of files and the number of directories.
779  *
780  * Using this information we can see that a layout of 256 directories, each
781  * with 512 subdirectories and each of those having 512 files gives us
782  * 256*512*512 = 67108864 AFS files and directories. 
783  *
784  * The volume, vnode, uniquifier and data version, as well as the tag
785  * are required, either for finding the file or for salvaging. It's best to 
786  * restrict the name to something that can be mapped into 64 bits so the
787  * "Inode" is easily comparable (using "==") to other "Inodes". The tag
788  * is used to distinguish between different versions of the same file
789  * which are currently in the RW and clones of a volume. See "Link Table
790  * Organization" below for more information on the tag. The tag is 
791  * required in the name of the file to ensure a unique name. 
792  *
793  * We can store data in the uid, gid and mode bits of the files, provided
794  * the directories have root only access. This gives us 15 bits for each
795  * of uid and gid (GNU chown considers 65535 to mean "don't change").
796  * There are 9 available mode bits. Adn we need to store a total of 
797  * 32 (volume id) + 26 (vnode) + 32 (uniquifier) + 32 (data-version) + 3 (tag)
798  * or 131 bits somewhere. 
799  *
800  * The format of a file name for a regular file is:
801  * /vicepX/AFSIDat/V1/V2/AA/BB/<tag><uniq><vno>
802  * V1 - low 8 bits of RW volume id
803  * V2 - all bits of RW volume id
804  * AA - high 8 bits of vnode number.
805  * BB - next 9 bits of vnode number.
806  * <tag><uniq><vno> - file name
807  *
808  * Volume special files are stored in a separate directory:
809  * /vicepX/AFSIDat/V1/V2/special/<tag><uniq><vno>
810  *
811  *
812  * The vnode is hashed into the directory using the high bits of the
813  * vnode number. This is so that consecutively created vnodes are in
814  * roughly the same area on the disk. This will at least be optimal if
815  * the user is creating many files in the same AFS directory. The name
816  * should be formed so that the leading characters are different as quickly
817  * as possible, leading to faster discards of incorrect matches in the
818  * lookup code.
819  * 
820  */
821
822
823 /************************************************************************
824  *  Link Table Organization
825  ************************************************************************
826  *
827  * The link table volume special file is used to hold the link counts that
828  * are held in the inodes in inode based AFS vice filesystems. For user
829  * space access, the link counts are being kept in a separate
830  * volume special file. The file begins with the usual version stamp
831  * information and is then followed by one row per vnode number. vnode 0
832  * is used to hold the link count of the link table itself. That is because
833  * the same link table is shared among all the volumes of the volume group
834  * and is deleted only when the last volume of a volume group is deleted.
835  *
836  * Within each row, the columns are 3 bits wide. They can each hold a 0 based
837  * link count from 0 through 7. Each colume represents a unique instance of
838  * that vnode. Say we have a file shared between the RW and a RO and a
839  * different version of the file (or a different uniquifer) for the BU volume.
840  * Then one column would be holding the link count of 2 for the RW and RO
841  * and a different column would hold the link count of 1 for the BU volume.
842  * Note that we allow only 5 volumes per file, giving 15 bits used in the
843  * short.
844  */
845 #define LINKTABLE_WIDTH 2
846 #define LINKTABLE_SHIFT 1       /* log 2 = 1 */
847
848 static void
849 namei_GetLCOffsetAndIndexFromIno(Inode ino, afs_foff_t * offset, int *index)
850 {
851     int toff = (int)(ino & NAMEI_VNODEMASK);
852     int tindex = (int)((ino >> NAMEI_TAGSHIFT) & NAMEI_TAGMASK);
853
854     *offset = (afs_foff_t) ((toff << LINKTABLE_SHIFT) + 8);     /* * 2 + sizeof stamp */
855     *index = (tindex << 1) + tindex;
856 }
857
858
859 /* namei_GetLinkCount
860  * If lockit is set, lock the file and leave it locked upon a successful
861  * return.
862  */
863 int
864 namei_GetLinkCount(FdHandle_t * h, Inode ino, int lockit)
865 {
866     unsigned short row = 0;
867     afs_foff_t offset;
868     int index;
869
870     namei_GetLCOffsetAndIndexFromIno(ino, &offset, &index);
871
872     if (lockit) {
873 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV)
874         if (lockf(h->fd_fd, F_LOCK, 0) < 0)
875 #else
876         if (flock(h->fd_fd, LOCK_EX) < 0)
877 #endif
878             return -1;
879     }
880
881     if (afs_lseek(h->fd_fd, offset, SEEK_SET) == -1)
882         goto bad_getLinkByte;
883
884     if (read(h->fd_fd, (char *)&row, sizeof(row)) != sizeof(row)) {
885         goto bad_getLinkByte;
886     }
887
888     return (int)((row >> index) & NAMEI_TAGMASK);
889
890   bad_getLinkByte:
891     if (lockit)
892 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV)
893         lockf(h->fd_fd, F_ULOCK, 0);
894 #else
895         flock(h->fd_fd, LOCK_UN);
896 #endif
897     return -1;
898 }
899
900 /* Return a free column index for this vnode. */
901 static int
902 GetFreeTag(IHandle_t * ih, int vno)
903 {
904     FdHandle_t *fdP;
905     afs_foff_t offset;
906     int col;
907     int coldata;
908     short row;
909     int code;
910
911
912     fdP = IH_OPEN(ih);
913     if (fdP == NULL)
914         return -1;
915
916     /* Only one manipulates at a time. */
917 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV)
918     if (lockf(fdP->fd_fd, F_LOCK, 0) < 0) {
919 #else
920     if (flock(fdP->fd_fd, LOCK_EX) < 0) {
921 #endif
922         FDH_REALLYCLOSE(fdP);
923         return -1;
924     }
925
926     offset = (vno << LINKTABLE_SHIFT) + 8;      /* * 2 + sizeof stamp */
927     if (afs_lseek(fdP->fd_fd, offset, SEEK_SET) == -1) {
928         goto badGetFreeTag;
929     }
930
931     code = read(fdP->fd_fd, (char *)&row, sizeof(row));
932     if (code != sizeof(row)) {
933         if (code != 0)
934             goto badGetFreeTag;
935         row = 0;
936     }
937
938     /* Now find a free column in this row and claim it. */
939     for (col = 0; col < NAMEI_MAXVOLS; col++) {
940         coldata = 7 << (col * 3);
941         if ((row & coldata) == 0)
942             break;
943     }
944     if (col >= NAMEI_MAXVOLS)
945         goto badGetFreeTag;
946
947     coldata = 1 << (col * 3);
948     row |= coldata;
949
950     if (afs_lseek(fdP->fd_fd, offset, SEEK_SET) == -1) {
951         goto badGetFreeTag;
952     }
953     if (write(fdP->fd_fd, (char *)&row, sizeof(row)) != sizeof(row)) {
954         goto badGetFreeTag;
955     }
956     FDH_SYNC(fdP);
957 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV)
958     lockf(fdP->fd_fd, F_ULOCK, 0);
959 #else
960     flock(fdP->fd_fd, LOCK_UN);
961 #endif
962     FDH_REALLYCLOSE(fdP);
963     return col;;
964
965   badGetFreeTag:
966 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV)
967     lockf(fdP->fd_fd, F_ULOCK, 0);
968 #else
969     flock(fdP->fd_fd, LOCK_UN);
970 #endif
971     FDH_REALLYCLOSE(fdP);
972     return -1;
973 }
974
975
976
977 /* namei_SetLinkCount
978  * If locked is set, assume file is locked. Otherwise, lock file before
979  * proceeding to modify it.
980  */
981 int
982 namei_SetLinkCount(FdHandle_t * fdP, Inode ino, int count, int locked)
983 {
984     afs_foff_t offset;
985     int index;
986     unsigned short row;
987     int junk;
988     int code = -1;
989
990     namei_GetLCOffsetAndIndexFromIno(ino, &offset, &index);
991
992     if (!locked) {
993 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV)
994         if (lockf(fdP->fd_fd, F_LOCK, 0) < 0) {
995 #else
996         if (flock(fdP->fd_fd, LOCK_EX) < 0) {
997 #endif
998             return -1;
999         }
1000     }
1001     if (afs_lseek(fdP->fd_fd, offset, SEEK_SET) == -1) {
1002         errno = EBADF;
1003         goto bad_SetLinkCount;
1004     }
1005
1006
1007     code = read(fdP->fd_fd, (char *)&row, sizeof(row));
1008     if (code != sizeof(row)) {
1009         if (code != 0) {
1010             errno = EBADF;
1011             goto bad_SetLinkCount;
1012         }
1013         row = 0;
1014     }
1015
1016     junk = 7 << index;
1017     count <<= index;
1018     row &= (unsigned short)~junk;
1019     row |= (unsigned short)count;
1020
1021     if (afs_lseek(fdP->fd_fd, offset, SEEK_SET) == -1) {
1022         errno = EBADF;
1023         goto bad_SetLinkCount;
1024     }
1025
1026     if (write(fdP->fd_fd, (char *)&row, sizeof(short)) != sizeof(short)) {
1027         errno = EBADF;
1028         goto bad_SetLinkCount;
1029     }
1030     FDH_SYNC(fdP);
1031
1032     code = 0;
1033
1034
1035   bad_SetLinkCount:
1036 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV)
1037     lockf(fdP->fd_fd, F_ULOCK, 0);
1038 #else
1039     flock(fdP->fd_fd, LOCK_UN);
1040 #endif
1041
1042     return code;
1043 }
1044
1045
1046 /* ListViceInodes - write inode data to a results file. */
1047 static int DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
1048                        int volid);
1049 static int DecodeVolumeName(char *name, int *vid);
1050 static int namei_ListAFSSubDirs(IHandle_t * dirIH,
1051                                 int (*write_fun) (FILE *,
1052                                                   struct ViceInodeInfo *,
1053                                                   char *, char *), FILE * fp,
1054                                 int (*judgeFun) (struct ViceInodeInfo *,
1055                                                  int vid, void *),
1056                                 int singleVolumeNumber, void *rock);
1057
1058
1059 /* WriteInodeInfo
1060  *
1061  * Write the inode data to the results file. 
1062  *
1063  * Returns -2 on error, 0 on success.
1064  *
1065  * This is written as a callback simply so that other listing routines
1066  * can use the same inode reading code.
1067  */
1068 static int
1069 WriteInodeInfo(FILE * fp, struct ViceInodeInfo *info, char *dir, char *name)
1070 {
1071     int n;
1072     n = fwrite(info, sizeof(*info), 1, fp);
1073     return (n == 1) ? 0 : -2;
1074 }
1075
1076
1077 int mode_errors;                /* Number of errors found in mode bits on directories. */
1078 void
1079 VerifyDirPerms(char *path)
1080 {
1081     struct afs_stat status;
1082
1083     if (afs_stat(path, &status) < 0) {
1084         Log("Unable to stat %s. Please manually verify mode bits for this"
1085             " directory\n", path);
1086     } else {
1087         if (((status.st_mode & 0777) != 0700) || (status.st_uid != 0))
1088             mode_errors++;
1089     }
1090 }
1091
1092 /* ListViceInodes
1093  * Fill the results file with the requested inode information.
1094  *
1095  * Return values:
1096  *  0 - success
1097  * -1 - complete failure, salvage should terminate.
1098  * -2 - not enough space on partition, salvager has error message for this.
1099  *
1100  * This code optimizes single volume salvages by just looking at that one
1101  * volume's directory. 
1102  *
1103  * If the resultFile is NULL, then don't call the write routine.
1104  */
1105 int
1106 ListViceInodes(char *devname, char *mountedOn, char *resultFile,
1107                int (*judgeInode) (struct ViceInodeInfo * info, int vid, void *rock),
1108                int singleVolumeNumber, int *forcep, int forceR, char *wpath, 
1109                void *rock)
1110 {
1111     FILE *fp = (FILE *) - 1;
1112     int ninodes;
1113     struct afs_stat status;
1114
1115     if (resultFile) {
1116         fp = afs_fopen(resultFile, "w");
1117         if (!fp) {
1118             Log("Unable to create inode description file %s\n", resultFile);
1119             return -1;
1120         }
1121     }
1122
1123     /* Verify protections on directories. */
1124     mode_errors = 0;
1125     VerifyDirPerms(mountedOn);
1126
1127     ninodes =
1128         namei_ListAFSFiles(mountedOn, WriteInodeInfo, fp, judgeInode,
1129                            singleVolumeNumber, rock);
1130
1131     if (!resultFile)
1132         return ninodes;
1133
1134     if (ninodes < 0) {
1135         fclose(fp);
1136         return ninodes;
1137     }
1138
1139     if (fflush(fp) == EOF) {
1140         Log("Unable to successfully flush inode file for %s\n", mountedOn);
1141         fclose(fp);
1142         return -2;
1143     }
1144     if (fsync(fileno(fp)) == -1) {
1145         Log("Unable to successfully fsync inode file for %s\n", mountedOn);
1146         fclose(fp);
1147         return -2;
1148     }
1149     if (fclose(fp) == EOF) {
1150         Log("Unable to successfully close inode file for %s\n", mountedOn);
1151         return -2;
1152     }
1153
1154     /*
1155      * Paranoia:  check that the file is really the right size
1156      */
1157     if (afs_stat(resultFile, &status) == -1) {
1158         Log("Unable to successfully stat inode file for %s\n", mountedOn);
1159         return -2;
1160     }
1161     if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
1162         Log("Wrong size (%d instead of %d) in inode file for %s\n",
1163             status.st_size, ninodes * sizeof(struct ViceInodeInfo),
1164             mountedOn);
1165         return -2;
1166     }
1167     return 0;
1168 }
1169
1170
1171 /* namei_ListAFSFiles
1172  *
1173  * Collect all the matching AFS files on the drive.
1174  * If singleVolumeNumber is non-zero, just return files for that volume.
1175  *
1176  * Returns <0 on error, else number of files found to match.
1177  */
1178 int
1179 namei_ListAFSFiles(char *dev,
1180                    int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
1181                                     char *), FILE * fp,
1182                    int (*judgeFun) (struct ViceInodeInfo *, int, void *),
1183                    int singleVolumeNumber, void *rock)
1184 {
1185     IHandle_t ih;
1186     namei_t name;
1187     int ninodes = 0;
1188     DIR *dirp1, *dirp2;
1189     struct dirent *dp1, *dp2;
1190     char path2[512];
1191 #ifdef DELETE_ZLC
1192     static void FreeZLCList(void);
1193 #endif
1194
1195     memset((void *)&ih, 0, sizeof(IHandle_t));
1196     ih.ih_dev = volutil_GetPartitionID(dev);
1197
1198     if (singleVolumeNumber) {
1199         ih.ih_vid = singleVolumeNumber;
1200         namei_HandleToVolDir(&name, &ih);
1201         ninodes =
1202             namei_ListAFSSubDirs(&ih, writeFun, fp, judgeFun,
1203                                  singleVolumeNumber, rock);
1204         if (ninodes < 0)
1205             return ninodes;
1206     } else {
1207         /* Find all volume data directories and descend through them. */
1208         namei_HandleToInodeDir(&name, &ih);
1209         ninodes = 0;
1210         dirp1 = opendir(name.n_path);
1211         if (!dirp1)
1212             return 0;
1213         while ((dp1 = readdir(dirp1))) {
1214             if (*dp1->d_name == '.')
1215                 continue;
1216             (void)strcpy(path2, name.n_path);
1217             (void)strcat(path2, "/");
1218             (void)strcat(path2, dp1->d_name);
1219             dirp2 = opendir(path2);
1220             if (dirp2) {
1221                 while ((dp2 = readdir(dirp2))) {
1222                     if (*dp2->d_name == '.')
1223                         continue;
1224                     if (!DecodeVolumeName(dp2->d_name, &ih.ih_vid)) {
1225                         ninodes +=
1226                             namei_ListAFSSubDirs(&ih, writeFun, fp, judgeFun,
1227                                                  0, rock);
1228                     }
1229                 }
1230                 closedir(dirp2);
1231             }
1232         }
1233         closedir(dirp1);
1234     }
1235 #ifdef DELETE_ZLC
1236     FreeZLCList();
1237 #endif
1238     return ninodes;
1239 }
1240
1241
1242
1243 /* namei_ListAFSSubDirs
1244  *
1245  *
1246  * Return values:
1247  * < 0 - an error
1248  * > = 0 - number of AFS files found.
1249  */
1250 static int
1251 namei_ListAFSSubDirs(IHandle_t * dirIH,
1252                      int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
1253                                       char *), FILE * fp,
1254                      int (*judgeFun) (struct ViceInodeInfo *, int, void *),
1255                      int singleVolumeNumber, void *rock)
1256 {
1257     IHandle_t myIH = *dirIH;
1258     namei_t name;
1259     char path1[512], path2[512], path3[512];
1260     DIR *dirp1, *dirp2, *dirp3;
1261     struct dirent *dp1, *dp2, *dp3;
1262     struct ViceInodeInfo info;
1263     FdHandle_t linkHandle;
1264     int ninodes = 0;
1265 #ifdef DELETE_ZLC
1266     int i;
1267     static void AddToZLCDeleteList(char dir, char *name);
1268     static void DeleteZLCFiles(char *path);
1269 #endif
1270
1271     namei_HandleToVolDir(&name, &myIH);
1272     (void)strcpy(path1, name.n_path);
1273
1274     /* Do the directory containing the special files first to pick up link
1275      * counts.
1276      */
1277     (void)strcat(path1, "/");
1278     (void)strcat(path1, NAMEI_SPECDIR);
1279
1280     linkHandle.fd_fd = -1;
1281     dirp1 = opendir(path1);
1282     if (dirp1) {
1283         while ((dp1 = readdir(dirp1))) {
1284             if (*dp1->d_name == '.')
1285                 continue;
1286             if (DecodeInode(path1, dp1->d_name, &info, myIH.ih_vid) < 0)
1287                 continue;
1288             if (info.u.param[2] != VI_LINKTABLE) {
1289                 info.linkCount = 1;
1290             } else {
1291                 /* Open this handle */
1292                 (void)afs_snprintf(path2, sizeof path2, "%s/%s", path1,
1293                                    dp1->d_name);
1294                 linkHandle.fd_fd = afs_open(path2, O_RDONLY, 0666);
1295                 info.linkCount =
1296                     namei_GetLinkCount(&linkHandle, (Inode) 0, 0);
1297             }
1298             if (judgeFun && !(*judgeFun) (&info, singleVolumeNumber, rock))
1299                 continue;
1300
1301             if ((*writeFun) (fp, &info, path1, dp1->d_name) < 0) {
1302                 if (linkHandle.fd_fd >= 0)
1303                     close(linkHandle.fd_fd);
1304                 closedir(dirp1);
1305                 return -1;
1306             }
1307             ninodes++;
1308         }
1309         closedir(dirp1);
1310     }
1311
1312     /* Now run through all the other subdirs */
1313     namei_HandleToVolDir(&name, &myIH);
1314     (void)strcpy(path1, name.n_path);
1315
1316     dirp1 = opendir(path1);
1317     if (dirp1) {
1318         while ((dp1 = readdir(dirp1))) {
1319             if (*dp1->d_name == '.')
1320                 continue;
1321             if (!strcmp(dp1->d_name, NAMEI_SPECDIR))
1322                 continue;
1323
1324             /* Now we've got a next level subdir. */
1325             (void)strcpy(path2, path1);
1326             (void)strcat(path2, "/");
1327             (void)strcat(path2, dp1->d_name);
1328             dirp2 = opendir(path2);
1329             if (dirp2) {
1330                 while ((dp2 = readdir(dirp2))) {
1331                     if (*dp2->d_name == '.')
1332                         continue;
1333
1334                     /* Now we've got to the actual data */
1335                     (void)strcpy(path3, path2);
1336                     (void)strcat(path3, "/");
1337                     (void)strcat(path3, dp2->d_name);
1338                     dirp3 = opendir(path3);
1339                     if (dirp3) {
1340                         while ((dp3 = readdir(dirp3))) {
1341                             if (*dp3->d_name == '.')
1342                                 continue;
1343                             if (DecodeInode
1344                                 (path3, dp3->d_name, &info, myIH.ih_vid) < 0)
1345                                 continue;
1346                             info.linkCount =
1347                                 namei_GetLinkCount(&linkHandle,
1348                                                    info.inodeNumber, 0);
1349                             if (info.linkCount == 0) {
1350 #ifdef DELETE_ZLC
1351                                 Log("Found 0 link count file %s/%s, deleting it.\n", path3, dp3->d_name);
1352                                 AddToZLCDeleteList((char)i, dp3->d_name);
1353 #else
1354                                 Log("Found 0 link count file %s/%s.\n", path3,
1355                                     dp3->d_name);
1356 #endif
1357                                 continue;
1358                             }
1359                             if (judgeFun
1360                                 && !(*judgeFun) (&info, singleVolumeNumber, rock))
1361                                 continue;
1362
1363                             if ((*writeFun) (fp, &info, path3, dp3->d_name) <
1364                                 0) {
1365                                 close(linkHandle.fd_fd);
1366                                 closedir(dirp3);
1367                                 closedir(dirp2);
1368                                 closedir(dirp1);
1369                                 return -1;
1370                             }
1371                             ninodes++;
1372                         }
1373                         closedir(dirp3);
1374                     }
1375                 }
1376                 closedir(dirp2);
1377             }
1378         }
1379         closedir(dirp1);
1380     }
1381
1382     if (linkHandle.fd_fd >= 0)
1383         close(linkHandle.fd_fd);
1384     if (!ninodes) {
1385         /* Then why does this directory exist? Blow it away. */
1386         namei_HandleToVolDir(&name, dirIH);
1387         namei_RemoveDataDirectories(&name);
1388     }
1389
1390     return ninodes;
1391 }
1392
1393 static int
1394 DecodeVolumeName(char *name, int *vid)
1395 {
1396     if (strlen(name) <= 2)
1397         return -1;
1398     *vid = (int)flipbase64_to_int64(name);
1399     return 0;
1400 }
1401
1402
1403 /* DecodeInode
1404  *
1405  * Get the inode number from the name.
1406  * Get
1407  */
1408 static int
1409 DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info, int volid)
1410 {
1411     char fpath[512];
1412     struct afs_stat status;
1413     int parm, tag;
1414
1415     (void)strcpy(fpath, dpath);
1416     (void)strcat(fpath, "/");
1417     (void)strcat(fpath, name);
1418
1419     if (afs_stat(fpath, &status) < 0) {
1420         return -1;
1421     }
1422
1423     info->byteCount = status.st_size;
1424     info->inodeNumber = (Inode) flipbase64_to_int64(name);
1425
1426     GetOGMFromStat(&status, &parm, &tag);
1427     if ((info->inodeNumber & NAMEI_INODESPECIAL) == NAMEI_INODESPECIAL) {
1428         /* p1 - vid, p2 - -1, p3 - type, p4 - rwvid */
1429         info->u.param[0] = parm;
1430         info->u.param[1] = -1;
1431         info->u.param[2] = tag;
1432         info->u.param[3] = volid;
1433     } else {
1434         /* p1 - vid, p2 - vno, p3 - uniq, p4 - dv */
1435         info->u.param[0] = volid;
1436         info->u.param[1] = (int)(info->inodeNumber & NAMEI_VNODEMASK);
1437         info->u.param[2] = (int)((info->inodeNumber >> NAMEI_UNIQSHIFT)
1438                                  & (Inode) NAMEI_UNIQMASK);
1439         info->u.param[3] = parm;
1440     }
1441     return 0;
1442 }
1443
1444 /*
1445  * Convert the VolumeInfo file from RO to RW
1446  * this routine is called by namei_convertROtoRWvolume()
1447  */
1448
1449 static afs_int32
1450 convertVolumeInfo(fdr, fdw, vid)
1451      int fdr;
1452      int fdw;
1453      afs_uint32 vid;
1454 {
1455     struct VolumeDiskData vd;
1456     char *p;
1457
1458     if (read(fdr, &vd, sizeof(struct VolumeDiskData)) !=
1459         sizeof(struct VolumeDiskData)) {
1460         Log("1 convertVolumeInfo: read failed for %lu with code %d\n", vid,
1461             errno);
1462         return -1;
1463     }
1464     vd.restoredFromId = vd.id;  /* remember the RO volume here */
1465     vd.cloneId = vd.id;
1466     vd.id = vd.parentId;
1467     vd.type = RWVOL;
1468     vd.dontSalvage = 0;
1469     vd.uniquifier += 5000;      /* just in case there are still file copies from
1470                                  * the old RW volume around */
1471     p = strrchr(vd.name, '.');
1472     if (p && !strcmp(p, ".readonly")) {
1473         memset(p, 0, 9);
1474     }
1475     if (write(fdw, &vd, sizeof(struct VolumeDiskData)) !=
1476         sizeof(struct VolumeDiskData)) {
1477         Log("1 convertVolumeInfo: write failed for %lu with code %d\n", vid,
1478             errno);
1479         return -1;
1480     }
1481     return 0;
1482 }
1483
1484 /*
1485  * Convert a RO-volume into a RW-volume
1486  *
1487  * This function allows to recover very fast from the loss of a partition
1488  * from RO-copies if all RO-Copies exist on another partition.
1489  * Then these RO-volumes can be made to the new RW-volumes.
1490  * Backup of RW-volumes then consists in "vos release".
1491  *
1492  * We must make sure in this partition exists only the RO-volume which
1493  * is typical for remote replicas.
1494  *
1495  * Then the linktable is already ok,
1496  *      the vnode files need to be renamed
1497  *      the volinfo file needs to be replaced by another one with
1498  *                      slightly different contents and new name.
1499  * The volume header file of the RO-volume in the /vicep<x> directory
1500  * is destroyed by this call. A new header file for the RW-volume must
1501  * be created after return from this routine.
1502  */
1503
1504 int
1505 namei_ConvertROtoRWvolume(IHandle_t * h, afs_uint32 vid)
1506 {
1507     namei_t n;
1508     char dir_name[512], oldpath[512], newpath[512];
1509     char smallName[64];
1510     char largeName[64];
1511     char infoName[64];
1512     IHandle_t t_ih;
1513     char infoSeen = 0;
1514     char smallSeen = 0;
1515     char largeSeen = 0;
1516     char linkSeen = 0;
1517     int code, fd, fd2;
1518     char *p;
1519     DIR *dirp;
1520     struct dirent *dp;
1521     struct ViceInodeInfo info;
1522
1523     namei_HandleToName(&n, h);
1524     strcpy(dir_name, n.n_path);
1525     p = strrchr(dir_name, '/');
1526     *p = 0;
1527     dirp = opendir(dir_name);
1528     if (!dirp) {
1529         Log("1 namei_ConvertROtoRWvolume: Could not opendir(%s)\n", dir_name);
1530         return EIO;
1531     }
1532
1533     while ((dp = readdir(dirp))) {
1534         /* struct ViceInodeInfo info; */
1535
1536         if (*dp->d_name == '.')
1537             continue;
1538         if (DecodeInode(dir_name, dp->d_name, &info, h->ih_vid) < 0) {
1539             Log("1 namei_ConvertROtoRWvolume: DecodeInode failed for %s/%s\n",
1540                 dir_name, dp->d_name);
1541             closedir(dirp);
1542             return -1;
1543         }
1544         if (info.u.param[1] != -1) {
1545             Log("1 namei_ConvertROtoRWvolume: found other than volume special file %s/%s\n", dir_name, dp->d_name);
1546             closedir(dirp);
1547             return -1;
1548         }
1549         if (info.u.param[0] != vid) {
1550             if (info.u.param[0] == h->ih_vid) {
1551                 if (info.u.param[2] == VI_LINKTABLE) {  /* link table */
1552                     linkSeen = 1;
1553                     continue;
1554                 }
1555             }
1556             Log("1 namei_ConvertROtoRWvolume: found special file %s/%s for volume %lu\n", dir_name, dp->d_name, info.u.param[0]);
1557             closedir(dirp);
1558             return VVOLEXISTS;
1559         }
1560         if (info.u.param[2] == VI_VOLINFO) {    /* volume info file */
1561             strcpy(infoName, dp->d_name);
1562             infoSeen = 1;
1563         } else if (info.u.param[2] == VI_SMALLINDEX) {  /* small vnodes file */
1564             strcpy(smallName, dp->d_name);
1565             smallSeen = 1;
1566         } else if (info.u.param[2] == VI_LARGEINDEX) {  /* large vnodes file */
1567             strcpy(largeName, dp->d_name);
1568             largeSeen = 1;
1569         } else {
1570             closedir(dirp);
1571             Log("1 namei_ConvertROtoRWvolume: unknown type %d of special file found : %s/%s\n", info.u.param[2], dir_name, dp->d_name);
1572             return -1;
1573         }
1574     }
1575     closedir(dirp);
1576
1577     if (!infoSeen || !smallSeen || !largeSeen || !linkSeen) {
1578         Log("1 namei_ConvertROtoRWvolume: not all special files found in %s\n", dir_name);
1579         return -1;
1580     }
1581
1582     /*
1583      * If we come here then there was only a RO-volume and we can safely
1584      * proceed.
1585      */
1586
1587     memset(&t_ih, 0, sizeof(t_ih));
1588     t_ih.ih_dev = h->ih_dev;
1589     t_ih.ih_vid = h->ih_vid;
1590
1591     (void)afs_snprintf(oldpath, sizeof oldpath, "%s/%s", dir_name, infoName);
1592     fd = afs_open(oldpath, O_RDWR, 0);
1593     if (fd < 0) {
1594         Log("1 namei_ConvertROtoRWvolume: could not open RO info file: %s\n",
1595             oldpath);
1596         return -1;
1597     }
1598     t_ih.ih_ino = namei_MakeSpecIno(h->ih_vid, VI_VOLINFO);
1599     namei_HandleToName(&n, &t_ih);
1600     fd2 = afs_open(n.n_path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0);
1601     if (fd2 < 0) {
1602         Log("1 namei_ConvertROtoRWvolume: could not create RW info file: %s\n", n.n_path);
1603         close(fd);
1604         return -1;
1605     }
1606     code = convertVolumeInfo(fd, fd2, h->ih_vid);
1607     close(fd);
1608     if (code) {
1609         close(fd2);
1610         unlink(n.n_path);
1611         return -1;
1612     }
1613     SetOGM(fd2, h->ih_vid, 1);
1614     close(fd2);
1615
1616     t_ih.ih_ino = namei_MakeSpecIno(h->ih_vid, VI_SMALLINDEX);
1617     namei_HandleToName(&n, &t_ih);
1618     (void)afs_snprintf(newpath, sizeof newpath, "%s/%s", dir_name, smallName);
1619     fd = afs_open(newpath, O_RDWR, 0);
1620     if (fd < 0) {
1621         Log("1 namei_ConvertROtoRWvolume: could not open SmallIndex file: %s\n", newpath);
1622         return -1;
1623     }
1624     SetOGM(fd, h->ih_vid, 2);
1625     close(fd);
1626     link(newpath, n.n_path);
1627     unlink(newpath);
1628
1629     t_ih.ih_ino = namei_MakeSpecIno(h->ih_vid, VI_LARGEINDEX);
1630     namei_HandleToName(&n, &t_ih);
1631     (void)afs_snprintf(newpath, sizeof newpath, "%s/%s", dir_name, largeName);
1632     fd = afs_open(newpath, O_RDWR, 0);
1633     if (fd < 0) {
1634         Log("1 namei_ConvertROtoRWvolume: could not open LargeIndex file: %s\n", newpath);
1635         return -1;
1636     }
1637     SetOGM(fd, h->ih_vid, 3);
1638     close(fd);
1639     link(newpath, n.n_path);
1640     unlink(newpath);
1641
1642     unlink(oldpath);
1643     return 0;
1644 }
1645
1646 /* PrintInode
1647  *
1648  * returns a static string used to print either 32 or 64 bit inode numbers.
1649  */
1650 char *
1651 PrintInode(char *s, Inode ino)
1652 {
1653     static afs_ino_str_t result;
1654     if (!s)
1655         s = result;
1656
1657     (void)afs_snprintf(s, sizeof(afs_ino_str_t), "%llu", (afs_uintmax_t) ino);
1658
1659     return s;
1660 }
1661
1662
1663 #ifdef DELETE_ZLC
1664 /* Routines to facilitate removing zero link count files. */
1665 #define MAX_ZLC_NAMES 32
1666 #define MAX_ZLC_NAMELEN 16
1667 typedef struct zlcList_s {
1668     struct zlcList_s *zlc_next;
1669     int zlc_n;
1670     char zlc_names[MAX_ZLC_NAMES][MAX_ZLC_NAMELEN];
1671 } zlcList_t;
1672
1673 static zlcList_t *zlcAnchor = NULL;
1674 static zlcList_t *zlcCur = NULL;
1675
1676 static void
1677 AddToZLCDeleteList(char dir, char *name)
1678 {
1679     assert(strlen(name) <= MAX_ZLC_NAMELEN - 3);
1680
1681     if (!zlcCur || zlcCur->zlc_n >= MAX_ZLC_NAMES) {
1682         if (zlcCur && zlcCur->zlc_next)
1683             zlcCur = zlcCur->zlc_next;
1684         else {
1685             zlcList_t *tmp = (zlcList_t *) malloc(sizeof(zlcList_t));
1686             if (!tmp)
1687                 return;
1688             if (!zlcAnchor) {
1689                 zlcAnchor = tmp;
1690             } else {
1691                 zlcCur->zlc_next = tmp;
1692             }
1693             zlcCur = tmp;
1694             zlcCur->zlc_n = 0;
1695             zlcCur->zlc_next = NULL;
1696         }
1697     }
1698
1699     (void)sprintf(zlcCur->zlc_names[zlcCur->zlc_n], "%c\\%s", dir, name);
1700     zlcCur->zlc_n++;
1701 }
1702
1703 static void
1704 DeleteZLCFiles(char *path)
1705 {
1706     zlcList_t *z;
1707     int i;
1708     char fname[1024];
1709
1710     for (z = zlcAnchor; z; z = z->zlc_next) {
1711         for (i = 0; i < z->zlc_n; i++) {
1712             (void)sprintf(fname, "%s\\%s", path, z->zlc_names[i]);
1713             if (namei_unlink(fname) < 0) {
1714                 Log("ZLC: Can't unlink %s, dos error = %d\n", fname,
1715                     GetLastError());
1716             }
1717         }
1718         z->zlc_n = 0;           /* Can reuse space. */
1719     }
1720     zlcCur = zlcAnchor;
1721 }
1722
1723 static void
1724 FreeZLCList(void)
1725 {
1726     zlcList_t *tnext;
1727     zlcList_t *i;
1728
1729     i = zlcAnchor;
1730     while (i) {
1731         tnext = i->zlc_next;
1732         free(i);
1733         i = tnext;
1734     }
1735     zlcCur = zlcAnchor = NULL;
1736 }
1737 #endif
1738
1739 #endif /* AFS_NAMEI_ENV */