b5d03791fb61847f008aed8b708fb09cad3666c9
[openafs.git] / src / vol / listinodes.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 /*
11
12         System:         VICE-TWO
13         Module:         listinodes.c
14         Institution:    The Information Technology Center, Carnegie-Mellon University
15
16  */
17
18 #define ITC                     /* Required by inode.h */
19
20 #include <afsconfig.h>
21 #include <afs/param.h>
22
23 #include <string.h>
24
25
26 #ifndef AFS_NAMEI_ENV
27 #if defined(AFS_LINUX20_ENV) || defined(AFS_SUN4_ENV)
28 /* ListViceInodes
29  *
30  * Return codes:
31  * 0 - success
32  * -1 - Unable to read the inodes.
33  * -2 - Unable to completely write temp file. Produces warning message in log.
34  */
35 int
36 ListViceInodes(char *devname, char *mountedOn, char *resultFile,
37                afs_uint32 (*judgeInode) (), afs_uint32 judgeParam, int *forcep, int forceR,
38                char *wpath, void *rock)
39 {
40     Log("ListViceInodes not implemented for this platform!\n");
41     return -1;
42 }
43 #else
44 #include <ctype.h>
45 #include <sys/param.h>
46 #if defined(AFS_SGI_ENV)
47 #else
48 #ifdef  AFS_OSF_ENV
49 #include <ufs/fs.h>
50 #else /* AFS_OSF_ENV */
51 #ifdef AFS_VFSINCL_ENV
52 #define VFS
53 #ifdef    AFS_SUN5_ENV
54 #include <sys/fs/ufs_fs.h>
55 #else
56 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
57 #include <ufs/ufs/dinode.h>
58 #include <ufs/ffs/fs.h>
59 #define itod ino_to_fsba
60 #else
61 #include <ufs/fs.h>
62 #endif
63 #endif
64 #else /* AFS_VFSINCL_ENV */
65 #ifdef  AFS_AIX_ENV
66 #include <sys/filsys.h>
67 #else
68 #include <sys/fs.h>
69 #endif
70 #endif /* AFS_VFSINCL_ENV */
71 #endif /* AFS_OSF_ENV */
72 #include <sys/time.h>
73 #ifdef AFS_VFSINCL_ENV
74 #include <sys/vnode.h>
75 #ifdef    AFS_SUN5_ENV
76 #include <sys/fs/ufs_inode.h>
77 #else
78 #if !defined(AFS_DARWIN_ENV)
79 #include <ufs/inode.h>
80 #endif
81 #endif
82 #else /* AFS_VFSINCL_ENV */
83 #ifdef  AFS_OSF_ENV
84 #include <ufs/inode.h>
85 #else /* AFS_OSF_ENV */
86 #include <sys/inode.h>
87 #endif
88 #endif /* AFS_VFSINCL_ENV */
89 #endif /* AFS_SGI_ENV */
90 #include <afs/osi_inode.h>
91 #include <sys/file.h>
92 #include <stdio.h>
93 #include <rx/xdr.h>
94 #include <afs/afsint.h>
95 #include "nfs.h"
96 #include <afs/afssyscalls.h>
97 #include "viceinode.h"
98 #include <sys/stat.h>
99 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
100 #include <sys/ino.h>
101 #endif
102 #ifdef AFS_PTHREAD_ENV
103 #include <assert.h>
104 #else /* AFS_PTHREAD_ENV */
105 #include <afs/assert.h>
106 #endif /* AFS_PTHREAD_ENV */
107 #if defined(AFS_HPUX101_ENV)
108 #include <unistd.h>
109 #endif
110 #include "lock.h"
111 #include "ihandle.h"
112 #include "vnode.h"
113 #include "volume.h"
114 #include "volinodes.h"
115 #include "partition.h"
116 #include "fssync.h"
117
118 /*@+fcnmacros +macrofcndecl@*/
119 #ifdef O_LARGEFILE
120 #ifdef S_SPLINT_S
121 extern off64_t afs_lseek(int FD, off64_t O, int F);
122 #endif /*S_SPLINT_S */
123 #define afs_lseek(FD, O, F)   lseek64(FD, (off64_t) (O), F)
124 #define afs_stat      stat64
125 #define afs_fstat     fstat64
126 #define afs_open      open64
127 #define afs_fopen     fopen64
128 #else /* !O_LARGEFILE */
129 #ifdef S_SPLINT_S
130 extern off_t afs_lseek(int FD, off_t O, int F);
131 #endif /*S_SPLINT_S */
132 #define afs_lseek(FD, O, F)   lseek(FD, (off_t) (O), F)
133 #define afs_stat      stat
134 #define afs_fstat     fstat
135 #define afs_open      open
136 #define afs_fopen     fopen
137 #endif /* !O_LARGEFILE */
138 /*@=fcnmacros =macrofcndecl@*/
139
140 /* Notice:  parts of this module have been cribbed from vfsck.c */
141
142 #define ROOTINODE       2
143 static char *partition;
144 int Testing=0;
145 int pfd;
146
147 #ifdef  AFS_AIX32_ENV
148 #include <jfs/filsys.h>
149
150 #ifndef FSBSIZE
151 #define FSBSIZE         (4096)  /* filesystem block size        */
152 #define FSBSHIFT        (12)    /* log2(FSBSIZE)                */
153 #define FSBMASK         (FSBSIZE - 1)   /* FSBSIZE mask                 */
154
155 #define MIN_FSIZE       DISKMAP_B       /* minimum fs size (FSblocks)   */
156 #define LAST_RSVD_I     15      /* last reserved inode          */
157 #endif
158
159 #ifndef INOPB
160 /*
161  * This will hopefully eventually make it into the system include files
162  */
163 #define INOPB           (FSBSIZE / sizeof (struct dinode))
164 #endif
165
166 #ifdef AFS_AIX41_ENV
167 int fragsize;
168 int iagsize;
169 int ag512;
170 int agblocks;
171 #endif /* AFS_AIX41_ENV */
172
173 /*
174  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
175  XX This was lifted from some `com/cmd/fs/fshlpr_aix3/Fs.h', which indicated X
176  XX a longing to see it make it into a readily accessible include file. XXXXXX
177  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
178  *
179  * itoo - inode number to offset within disk block
180  */
181 #undef itoo
182 #define itoo(x)         (int) ((unsigned)(x) % INOPB)
183
184 int Bsize = FSBSIZE;            /* block size for this system                   */
185 daddr_t fmax;                   /* total number of blocks n file system         */
186 ino_t imax, inum;               /* total number of I-nodes in file system       */
187
188 static struct superblock fs;
189 struct dinode *ginode();
190
191
192 int
193 ListViceInodes(char *devname, char *mountedOn, char *resultFile,
194                int (*judgeInode) (), afs_uint32 judgeParam, int *forcep, int forceR,
195                char *wpath, void *rock)
196 {
197     FILE *inodeFile = NULL;
198     char dev[50], rdev[51];
199     struct stat status;
200     struct dinode *p;
201     struct ViceInodeInfo info;
202     struct stat root_inode;
203     int ninodes = 0, err = 0;
204
205     pfd = -1;                   /* initialize so we don't close on error output below. */
206     *forcep = 0;
207     sync();
208     sleep(1);                   /* simulate operator    */
209     sync();
210     sleep(1);
211     sync();
212     sleep(1);
213
214     partition = mountedOn;
215     sprintf(dev, "/dev/%s", devname);
216     sprintf(rdev, "/dev/r%s", devname);
217
218     if (stat(mountedOn, &root_inode) < 0) {
219         Log("cannot stat: %s\n", mountedOn);
220         return -1;
221     }
222
223     if (root_inode.st_ino != ROOTDIR_I) {
224         Log("%s is not root of a filesystem\n", mountedOn);
225         return -1;
226     }
227
228
229     /*
230      * done with the superblock, now try to read the raw device.
231      */
232     if (ReadSuper(&fs, dev) < 0)
233         return -1;
234
235     switch (fs.s_fmod) {
236     default:
237     case FM_CLEAN:              /* clean and unmounted                  */
238         Log("Most peculiar - Super blk in FM_CLEAN state!\n");
239         goto out;
240     case FM_MOUNT:              /* mounted cleanly                      */
241         break;
242
243     case FM_MDIRTY:             /* dirty when mounted or commit fail    */
244     case FM_LOGREDO:            /* log redo attempted but failed        */
245         Log("File system %s is in a bad state.\n", rdev);
246         Log("Call your IBM representative.\n");
247         return -1;
248     }
249 #ifdef AFS_AIX42_ENV
250     if (IsBigFilesFileSystem(&fs, (char *)0)) {
251         Log("%s is a big files filesystem, can't salvage.\n", mountedOn);
252         return -1;
253     }
254 #else
255     if (strncmp(fs.s_magic, fsv3magic, strlen(fsv3magic)) != 0) {
256 #ifdef  AFS_AIX41_ENV
257         if ((strncmp(fs.s_magic, fsv3pmagic, strlen(fsv3pmagic)) != 0)
258             || (fs.s_version != fsv3pvers)) {
259             Log("Super block doesn't have the problem magic (%s vs v3magic %s v3pmagic %s)\n", fs.s_magic, fsv3magic, fsv3pmagic);
260             return -1;
261         }
262 #else
263         Log("Super block doesn't have the problem magic (%s vs v3magic %s)\n",
264             fs.s_magic, fsv3magic);
265         return -1;
266 #endif
267     }
268 #endif
269
270 #ifdef AFS_AIX41_ENV
271     fragsize = (fs.s_fragsize) ? fs.s_fragsize : FSBSIZE;
272     iagsize = (fs.s_iagsize) ? fs.s_iagsize : fs.s_agsize;
273     ag512 = fragsize * fs.s_agsize / 512;
274     agblocks = fragsize * fs.s_agsize >> BSHIFT;
275 #endif /* AFS_AIX41_ENV */
276
277     fmax = fs.s_fsize / (FSBSIZE / 512);        /* first invalid blk num */
278
279     pfd = afs_open(rdev, O_RDONLY);
280     if (pfd < 0) {
281         Log("Unable to open `%s' inode for reading\n", rdev);
282         return -1;
283     }
284
285     if (resultFile) {
286         inodeFile = fopen(resultFile, "w");
287         if (inodeFile == NULL) {
288             Log("Unable to create inode description file %s\n", resultFile);
289             goto out;
290         }
291     }
292
293     /*
294      * calculate the maximum number of inodes possible
295      */
296 #ifdef AFS_AIX41_ENV
297     imax = iagsize * (fs.s_fsize / ag512) - 1;
298 #else /* AFS_AIX41_ENV */
299     imax =
300         ((fmax / fs.s_agsize +
301           ((fmax % fs.s_agsize) >= fs.s_agsize / INOPB ? 1 : 0))
302          * fs.s_agsize) - 1;
303 #endif /* AFS_AIX41_ENV */
304
305     /*
306      * check for "FORCESALVAGE" equivalent:
307      *      LAST_RSVD_I is a vice inode, with dead beef, and
308      *      di_nlink == 2 to indicate the FORCE.
309      */
310     assert(p = ginode(LAST_RSVD_I));
311
312     if (p->di_vicemagic == VICEMAGIC && p->di_vicep1 == 0xdeadbeef
313         && p->di_nlink == 2) {
314         *forcep = 1;
315         idec(root_inode.st_dev, LAST_RSVD_I, 0xdeadbeef);
316     }
317
318     for (inum = LAST_RSVD_I + 1; inum <= imax; ++inum) {
319         if ((p = ginode(inum)) == NULL || p->di_vicemagic != VICEMAGIC
320             || (p->di_mode & IFMT) != IFREG)
321             continue;
322
323         info.inodeNumber = inum;
324         info.byteCount = p->di_size;
325         info.linkCount = p->di_nlink;
326         info.u.param[0] = p->di_vicep1;
327         info.u.param[1] = p->di_vicep2;
328         info.u.param[2] = p->di_vicep3;
329         info.u.param[3] = p->di_vicep4;
330
331         if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
332             continue;
333
334         if (inodeFile) {
335             if (fwrite(&info, sizeof info, 1, inodeFile) != 1) {
336                 Log("Error writing inode file for partition %s\n", partition);
337                 goto out;
338             }
339         }
340         ++ninodes;
341     }
342
343     if (inodeFile) {
344         if (fflush(inodeFile) == EOF) {
345             Log("Unable to successfully flush inode file for %s\n", partition);
346             err = -2;
347             goto out1;
348         }
349         if (fsync(fileno(inodeFile)) == -1) {
350             Log("Unable to successfully fsync inode file for %s\n", partition);
351             err = -2;
352             goto out1;
353         }
354         if (fclose(inodeFile) == EOF) {
355             Log("Unable to successfully close inode file for %s\n", partition);
356             err = -2;
357             goto out1;
358         }
359
360         /*
361          * Paranoia:  check that the file is really the right size
362          */
363         if (stat(resultFile, &status) == -1) {
364             Log("Unable to successfully stat inode file for %s\n", partition);
365             err = -2;
366             goto out1;
367         }
368         if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
369             Log("Wrong size (%d instead of %d) in inode file for %s\n",
370                 status.st_size, ninodes * sizeof(struct ViceInodeInfo),
371                 partition);
372             err = -2;
373             goto out1;
374         }
375     }
376     close(pfd);
377     return 0;
378
379   out:
380     err = -1;
381   out1:
382     if (pfd >= 0)
383         close(pfd);
384     if (inodeFile)
385         fclose(inodeFile);
386
387     return err;
388 }
389
390 /* Read in the superblock for devName */
391 int
392 ReadSuper(struct superblock *fs, char *devName)
393 {
394     int pfd;
395
396     pfd = afs_open(devName, O_RDONLY);
397     if (pfd < 0) {
398         Log("Unable to open inode on %s for reading superblock.\n", devName);
399         return -1;
400     }
401
402     if (bread(pfd, fs, SUPER_B, sizeof(struct superblock)) < 0) {
403         Log("Unable to read superblock on %s.\n", devName);
404         return -1;
405     }
406     close(pfd);
407     return (0);
408 }
409
410 #ifdef AFS_AIX42_ENV
411 /* IsBigFilesFileSystem returns 1 if it's a big files filesystem, 0 otherwise. */
412 int
413 IsBigFilesFileSystem(struct superblock *sb)
414 {
415     if ((strncmp(sb->s_magic, fsv3pmagic, 4) == 0)
416         && (sb->s_version == fsbigfile)
417         && (sb->s_bigexp))
418         return 1;
419     else
420         return 0;
421 }
422 #endif
423
424 struct dinode *
425 ginode(inum)
426 {
427     int ag;
428     daddr_t pblk;
429     struct dinode *dp;
430     static char buf[FSBSIZE];
431     static daddr_t last_blk = -1;
432
433 #ifdef AFS_AIX41_ENV
434     ag = inum / iagsize;
435     pblk =
436         (ag ==
437          0) ? INODES_B + inum / INOPB : ag * agblocks + (inum -
438                                                          ag * iagsize) /
439         INOPB;
440 #else /* AFS_AIX41_ENV */
441     ag = inum / fs.s_agsize;
442     pblk =
443         (ag ==
444          0) ? INODES_B + inum / INOPB : ag * fs.s_agsize + (inum -
445                                                             ag *
446                                                             fs.s_agsize) /
447         INOPB;
448 #endif /* AFS_AIX41_ENV */
449
450     if (last_blk != pblk) {
451         if (bread(pfd, buf, pblk, sizeof(buf)) < 0) {
452             last_blk = -1;
453             return 0;
454         }
455         last_blk = pblk;
456     }
457
458     dp = (struct dinode *)buf;
459     dp += itoo(inum);
460     return (dp);
461 }
462
463 #else /* !AFS_AIX31_ENV       */
464
465 #if defined(AFS_SGI_ENV)
466
467 /* libefs.h includes <assert.h>, which we don't want */
468 #define __ASSERT_H__
469
470 #ifdef AFS_SGI_XFS_IOPS_ENV
471 #include <dirent.h>
472 #include <afs/xfsattrs.h>
473 /* xfs_ListViceInodes
474  *
475  * xfs_ListViceInodes verifies and correct the XFS namespace as it collects
476  * the inode information. The name is required for the idec operation to work. 
477  * Steps 2 and 3 below are for the AFS_XFS_NAME_VERS == 1. If the name space
478  * changes, the algorithm will need to change. 
479  * 1) If the parent inode number does not match the directory's inod number,
480  *    change it in the attribute.
481  * 2) If the unqifier in the attribute does not match the name, rename the
482  *    file. This is done by doing an exclusive open, incrementing the tag
483  *    number until a file can be created. If the tag changes, then the
484  *    attribute will need updating.
485  * 3) If the tag in the attribute does not match the name, change the
486  *    attribute.
487  * 4) Verify uid = RW volume id and gid = XFS_VICEMAGIC.
488  *
489  */
490
491 /* xfs_VerifyInode
492  * 
493  * Does the verifications listed above.
494  * We can't change the names until the readdir is complete, so we set the
495  * rename flag if the file needs renaming.
496  */
497 int
498 xfs_VerifyInode(char *dir, uint64_t pino, char *name, i_list_inode_t * info,
499                 int *rename)
500 {
501     char path[1024];
502     int vno;
503     int update_pino = 0;
504     int update_tag = 0;
505     int update_chown = 0;
506     int retCode = 0;
507     char tmpName[32];
508     b64_string_t stmp;
509     int tag;
510
511     *rename = 0;
512     (void)sprintf(path, "%s/%s", dir, name);
513     /* Verify uid and gid fields */
514     if (info->ili_magic != XFS_VICEMAGIC) {
515         Log("%s  magic for %s/%s (inode %s) from %d to %d\n",
516             Testing ? "Would have changed" : "Changing", dir, name,
517             PrintInode(NULL, info->ili_info.inodeNumber), info->ili_magic,
518             XFS_VICEMAGIC);
519         if (!Testing)
520             update_chown = 1;
521     }
522
523     vno = info->ili_info.param[0];
524     if (info->ili_vno != AFS_XFS_VNO_CLIP(vno)) {
525         Log("%s volume id for %s/%s (inode %s) from %d to %d\n",
526             Testing ? "Would have changed" : "Changing", dir, name,
527             PrintInode(NULL, info->ili_info.inodeNumber), info->ili_vno,
528             AFS_XFS_VNO_CLIP(vno));
529         if (!Testing)
530             update_chown = 1;
531     }
532
533     if (update_chown) {
534         if (chown(path, AFS_XFS_VNO_CLIP(vno), XFS_VICEMAGIC) < 0) {
535             Log("Can't chown %s to uid=%d, gid=0x%x\n", path,
536                 AFS_XFS_VNO_CLIP(vno), XFS_VICEMAGIC);
537             retCode = -1;
538         }
539     }
540
541     /* Check Parent inode number. */
542     if (info->ili_pino != pino) {
543         afs_ino_str_t sino, sipino, spino;
544         (void)PrintInode(sino, info->ili_info.inodeNumber);
545         (void)PrintInode(sipino, info->ili_pino);
546         (void)PrintInode(spino, pino);
547         Log("%s parent ino for %s (inode %s) from %s to %s.\n",
548             Testing ? "Would have changed" : "Changing", path, sino, sipino,
549             spino);
550         if (!Testing)
551             update_pino = 1;
552     }
553
554     /* Verify the file name. */
555     (void)strcpy(tmpName, ".");
556     (void)strcat(tmpName, int_to_base64(stmp, info->ili_info.param[2]));
557     if (strncmp(name, tmpName, strlen(tmpName))) {
558         Log("%s name %s (inode %s) in directory %s, unique=%d, tag=%d\n",
559             Testing ? "Would have returned bad" : "Bad", name,
560             PrintInode(NULL, info->ili_info.inodeNumber), dir,
561             info->ili_info.param[2], info->ili_tag);
562         if (!Testing)
563             *rename = 1;
564     }
565
566     if (!*rename) {
567         /* update the tag? */
568         (void)strcat(tmpName, ".");
569         (void)strcat(tmpName, int_to_base64(stmp, info->ili_tag));
570         if (strcmp(name, tmpName)) {
571             char *p;
572             (void)strcpy(tmpName, name);
573             p = strchr(tmpName + 1, '.');
574             if (!p) {
575                 Log("No tag found on name %s (inode %s)in directory, %s.\n",
576                     name, PrintInode(NULL, info->ili_info.inodeNumber), dir,
577                     Testing ? "would have renamed" : "will rename");
578                 if (!Testing)
579                     *rename = 1;
580             } else {
581                 tag = base64_to_int(p + 1);
582                 Log("%s the tag for %s (inode %s) from %d to %d.\n",
583                     Testing ? "Would have changed" : "Will change", path,
584                     PrintInode(NULL, info->ili_info.inodeNumber), dir, tag,
585                     info->ili_tag);
586                 if (!Testing)
587                     update_tag = 1;
588             }
589         }
590     }
591
592     if (update_pino || update_tag) {
593         afs_xfs_attr_t attrs;
594         int length;
595
596         length = SIZEOF_XFS_ATTR_T;
597         if (attr_get(path, AFS_XFS_ATTR, (char *)&attrs, &length, ATTR_ROOT) <
598             0) {
599             Log("Can't get AFS attribute for %s\n", path);
600             return -1;
601         }
602         if (update_pino)
603             attrs.at_pino = pino;
604         if (update_tag)
605             attrs.at_tag = tag;
606         if (attr_set
607             (path, AFS_XFS_ATTR, (char *)&attrs, length,
608              ATTR_ROOT | ATTR_REPLACE) < 0) {
609             Log("Can't set AFS attribute into %s\n", path);
610             retCode = -1;
611         }
612     }
613
614     return retCode;
615 }
616
617 typedef struct {
618     int uniq;
619     char name[28];
620 } xfs_Rename_t;
621
622 int
623 xfs_RenameFiles(char *dir, xfs_Rename_t * renames, int n_renames)
624 {
625     int i, j;
626     char opath[128], nbase[128], npath[128];
627     afs_xfs_attr_t attrs;
628     int length = SIZEOF_XFS_ATTR_T;
629     b64_string_t stmp;
630     int tag;
631     int fd;
632
633     for (i = 0; i < n_renames; i++) {
634         (void)sprintf(opath, "%s/%s", dir, renames[i].name);
635         (void)sprintf(nbase, "%s/.%s", dir,
636                       int_to_base64(stmp, renames[i].uniq));
637         for (tag = 2, j = 0; j < 64; tag++, j++) {
638             (void)sprintf(npath, "%s.%s", nbase, int_to_base64(stmp, tag));
639             fd = afs_open(npath, O_CREAT | O_EXCL | O_RDWR, 0);
640             if (fd > 0) {
641                 close(fd);
642                 break;
643             }
644         }
645         if (j != 64) {
646             Log("Can't find a new name for %s\n", opath);
647             return -1;
648         }
649         if (rename(opath, npath) < 0) {
650             Log("Can't rename %s to %s\n", opath, npath);
651             return -1;
652         }
653         Log("Renamed %s to %s\n", opath, npath);
654         return 0;
655     }
656 }
657
658
659 int
660 xfs_ListViceInodes(char *devname, char *mountedOn, char *resultFile,
661                    int (*judgeInode) (), afs_uint32 judgeParam, int *forcep,
662                    int forceR, char *wpath, void *rock)
663 {
664     FILE *inodeFile = NULL;
665     i_list_inode_t info;
666     int info_size = sizeof(i_list_inode_t);
667     int fd;
668     DIR *top_dirp;
669     dirent64_t *top_direntp;
670     DIR *vol_dirp;
671     dirent64_t *vol_direntp;
672     struct stat64 sdirbuf;
673     struct stat64 sfilebuf;
674     afs_xfs_attr_t attrs;
675     afs_xfs_dattr_t dattrs;
676     int length;
677     char vol_dirname[1024];
678     int ninodes = 0;
679     int code = 0;
680     xfs_Rename_t *renames = (xfs_Rename_t *) 0;
681     int rename;
682 #define N_RENAME_STEP 64
683     int n_renames = 0;
684     int n_avail = 0;
685     uint64_t pino;
686     struct stat status;
687     int errors = 0;
688
689     *forcep = 0;
690
691     if (stat64(mountedOn, &sdirbuf) < 0) {
692         perror("xfs_ListViceInodes: stat64");
693         return -1;
694     }
695
696     if (resultFile) {
697         inodeFile = fopen(resultFile, "w");
698         if (inodeFile == NULL) {
699             Log("Unable to create inode description file %s\n", resultFile);
700             return -1;
701         }
702     }
703
704     if ((top_dirp = opendir(mountedOn)) == NULL) {
705         Log("Can't open directory %s to read inodes.\n", mountedOn);
706         return -1;
707     }
708
709     while (top_direntp = readdir64(top_dirp)) {
710         /* Only descend directories with the AFSDIR attribute set.
711          * Could also verify the contents of the atribute, but currently
712          * they are not used.
713          * Performance could be improved for single volume salvages by
714          * only going through the directory containing the volume's inodes.
715          * But I'm being complete as a first pass.
716          */
717         (void)sprintf(vol_dirname, "%s/%s", mountedOn, top_direntp->d_name);
718         length = SIZEOF_XFS_DATTR_T;
719         if (attr_get
720             (vol_dirname, AFS_XFS_DATTR, (char *)&dattrs, &length, ATTR_ROOT))
721             continue;
722
723         if ((vol_dirp = opendir(vol_dirname)) == NULL) {
724             if (errno == ENOTDIR)
725                 continue;
726             Log("Can't open directory %s to read inodes.\n", vol_dirname);
727             goto err1_exit;
728         }
729
730         pino = top_direntp->d_ino;
731         n_renames = 0;
732         while (vol_direntp = readdir64(vol_dirp)) {
733             if (vol_direntp->d_name[1] == '\0'
734                 || vol_direntp->d_name[1] == '.')
735                 continue;
736
737             info.ili_version = AFS_XFS_ILI_VERSION;
738             info_size = sizeof(i_list_inode_t);
739             code =
740                 ilistinode64(sdirbuf.st_dev, vol_direntp->d_ino, &info,
741                              &info_size);
742             if (code) {
743                 /* Where possible, give more explicit messages. */
744                 switch (errno) {
745                 case ENXIO:
746                 case ENOSYS:
747                     Log("%s (device id %d) is not on an XFS filesystem.\n",
748                         vol_dirname, sdirbuf.st_dev);
749                     goto err1_exit;
750                     break;
751                 case EINVAL:
752                 case E2BIG:
753                     if (info_size != sizeof(i_list_inode_t)
754                         || info.ili_version != AFS_XFS_ILI_VERSION) {
755                         Log("Version skew between kernel and salvager.\n");
756                         goto err1_exit;
757                     }
758                     break;
759                 }
760                 /* Continue, so we collect all the errors in the first pass. */
761                 Log("Error listing inode named %s/%s: %s\n", vol_dirname,
762                     vol_direntp->d_name, strerror(errno));
763                 errors++;
764                 continue;
765             }
766
767             if (info.ili_attr_version != AFS_XFS_ATTR_VERS) {
768                 Log("Unrecognized XFS attribute version %d in %s/%s. Upgrade salvager\n", info.ili_attr_version, vol_dirname, vol_direntp->d_name);
769                 goto err1_exit;
770             }
771
772             if (judgeInode && (*judgeInode) (&info.ili_info, judgeParam, rock) == 0)
773                 continue;
774
775             rename = 0;
776             if (xfs_VerifyInode
777                 (vol_dirname, pino, vol_direntp->d_name, &info,
778                  &rename) < 0) {
779                 errors++;
780             }
781
782             if (rename) {
783                 /* Add this name to the list of items to rename. */
784                 if (n_renames >= n_avail) {
785                     n_avail += N_RENAME_STEP;
786                     if (n_avail == N_RENAME_STEP)
787                         renames = (xfs_Rename_t *)
788                             malloc(n_avail * sizeof(xfs_Rename_t));
789                     else
790                         renames = (xfs_Rename_t *)
791                             realloc((char *)renames,
792                                     n_avail * sizeof(xfs_Rename_t));
793                     if (!renames) {
794                         Log("Can't %salloc %lu bytes for rename list.\n",
795                             (n_avail == N_RENAME_STEP) ? "m" : "re",
796                             n_avail * sizeof(xfs_Rename_t));
797                         goto err1_exit;
798                     }
799                 }
800                 (void)strcpy(renames[n_renames].name, vol_direntp->d_name);
801                 renames[n_renames].uniq = info.ili_info.param[2];
802                 n_renames++;
803             }
804
805             if (inodeFile) {
806                 if (fwrite
807                     (&info.ili_info, sizeof(vice_inode_info_t), 1, inodeFile)
808                     != 1) {
809                     Log("Error writing inode file for partition %s\n", mountedOn);
810                     goto err1_exit;
811                 }
812             }
813             ninodes++;
814
815         }                       /* end while vol_direntp */
816
817         closedir(vol_dirp);
818         vol_dirp = (DIR *) 0;
819         if (n_renames) {
820             Log("Renaming files.\n");
821             if (xfs_RenameFiles(vol_dirname, renames, n_renames) < 0) {
822                 goto err1_exit;
823             }
824         }
825     }
826
827     closedir(top_dirp);
828     if (renames)
829         free((char *)renames);
830     if (inodeFile) {
831         if (fflush(inodeFile) == EOF) {
832             ("Unable to successfully flush inode file for %s\n", mountedOn);
833             fclose(inodeFile);
834             return errors ? -1 : -2;
835         }
836         if (fsync(fileno(inodeFile)) == -1) {
837             Log("Unable to successfully fsync inode file for %s\n", mountedOn);
838             fclose(inodeFile);
839             return errors ? -1 : -2;
840         }
841         if (fclose(inodeFile) == EOF) {
842             Log("Unable to successfully close inode file for %s\n", mountedOn);
843             return errors ? -1 : -2;
844         }
845         /*
846          * Paranoia:  check that the file is really the right size
847          */
848         if (stat(resultFile, &status) == -1) {
849             Log("Unable to successfully stat inode file for %s\n", partition);
850             return errors ? -1 : -2;
851         }
852         if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
853             Log("Wrong size (%d instead of %d) in inode file for %s\n",
854                 status.st_size, ninodes * sizeof(struct ViceInodeInfo),
855                 partition);
856             return errors ? -1 : -2;
857         }
858     }
859
860     if (errors) {
861         Log("Errors encontered listing inodes, not salvaging partition.\n");
862         return -1;
863     }
864
865     return 0;
866
867   err1_exit:
868     if (vol_dirp)
869         closedir(vol_dirp);
870     if (top_dirp)
871         closedir(top_dirp);
872     if (renames)
873         free((char *)renames);
874     if (inodeFile)
875         fclose(inodeFile);
876     return -1;
877 }
878
879 #endif
880
881 int
882 ListViceInodes(char *devname, char *mountedOn, char *resultFile,
883                int (*judgeInode) (), afs_uint32 judgeParam, int *forcep, int forceR,
884                char *wpath, void *rock)
885 {
886     FILE *inodeFile = NULL;
887     char dev[50], rdev[51];
888     struct stat status;
889     struct efs_dinode *p;
890     struct ViceInodeInfo info;
891     struct stat root_inode;
892     int ninodes = 0, err = 0;
893     struct efs_dinode *dinodeBuf = NULL;
894     int last_cgno;
895     ino_t imax, inum;           /* total number of I-nodes in file system */
896
897     *forcep = 0;
898     sync();
899     sleep(1);                   /* simulate operator    */
900     sync();
901     sleep(1);
902     sync();
903     sleep(1);
904
905     if (stat(mountedOn, &root_inode) < 0) {
906         Log("cannot stat: %s\n", mountedOn);
907         return -1;
908     }
909 #ifdef AFS_SGI_XFS_IOPS_ENV
910     if (!strcmp("xfs", root_inode.st_fstype)) {
911         return xfs_ListViceInodes(devname, mountedOn, resultFile, judgeInode,
912                                   judgeParam, forcep, forceR, wpath, rock);
913     } else
914 #endif
915     {
916         Log("%s is not root of a filesystem\n", mountedOn);
917         return -1;
918     }
919 }
920
921 #else /* AFS_SGI_ENV */
922
923 #ifdef AFS_HPUX_ENV
924 #define SPERB   (MAXBSIZE / sizeof(short))
925 #define MAXNINDIR (MAXBSIZE / sizeof(daddr_t))
926
927 struct bufarea {
928     struct bufarea *b_next;     /* must be first */
929     daddr_t b_bno;
930     int b_size;
931     union {
932         char b_buf[MAXBSIZE];   /* buffer space */
933         short b_lnks[SPERB];    /* link counts */
934         daddr_t b_indir[MAXNINDIR];     /* indirect block */
935         struct fs b_fs;         /* super block */
936         struct cg b_cg;         /* cylinder group */
937     } b_un;
938     char b_dirty;
939 };
940 typedef struct bufarea BUFAREA;
941
942 BUFAREA sblk;
943 #define sblock sblk.b_un.b_fs
944 #endif /* AFS_HPUX_ENV */
945
946 extern char *afs_rawname();
947 int
948 ListViceInodes(char *devname, char *mountedOn, char *resultFile,
949                int (*judgeInode) (), afs_uint32 judgeParam, int *forcep, int forceR,
950                char *wpath, void *rock)
951 {
952     union {
953 #ifdef  AFS_AIX_ENV
954         struct filsys fs;
955         char block[BSIZE];
956 #else                           /* !AFS_AIX_ENV */
957         struct fs fs;
958         char block[SBSIZE];
959 #endif
960     } super;
961     int i, c, e, bufsize, code, err = 0;
962     FILE *inodeFile = NULL;
963     char dev[50], rdev[100], err1[512], *ptr1;
964     struct dinode *inodes = NULL, *einodes, *dptr;
965     struct stat status;
966     int ninodes = 0;
967     struct dinode *p;
968     struct ViceInodeInfo info;
969
970     *forcep = 0;
971     partition = mountedOn;
972     sprintf(rdev, "%s/%s", wpath, devname);
973     ptr1 = afs_rawname(rdev);
974     strcpy(rdev, ptr1);
975
976     sync();
977     /* Bletch:  this is terrible;  is there a better way to do this? Does this work? vfsck doesn't even sleep!! */
978 #ifdef  AFS_AIX_ENV
979     sleep(5);                   /* Trying a smaller one for aix */
980 #else
981     sleep(10);
982 #endif
983
984     pfd = afs_open(rdev, O_RDONLY);
985     if (pfd <= 0) {
986         sprintf(err1, "Could not open device %s to get inode list\n", rdev);
987         perror(err1);
988         return -1;
989     }
990 #ifdef  AFS_AIX_ENV
991     if (bread(pfd, (char *)&super.fs, SUPERB, sizeof super.fs) == -1) {
992 #else
993 #ifdef AFS_HPUX_ENV
994     if (bread(pfd, (char *)&sblock, SBLOCK, SBSIZE) == -1) {
995 #else
996     if (bread(pfd, super.block, SBLOCK, SBSIZE) == -1) {
997 #endif /* AFS_HPUX_ENV */
998 #endif
999         Log("Unable to read superblock, partition %s\n", partition);
1000         goto out;
1001     }
1002
1003     if (resultFile) {
1004         inodeFile = fopen(resultFile, "w");
1005         if (inodeFile == NULL) {
1006             Log("Unable to create inode description file %s\n", resultFile);
1007             goto out;
1008         }
1009     }
1010 #ifdef  AFS_AIX_ENV
1011     /*
1012      * char *FSlabel(), *fslabel=0;
1013      * fslabel = FSlabel(&super.fs);
1014      */
1015     if (super.fs.s_bsize == 0)
1016         super.fs.s_bsize = 512;
1017     if (super.fs.s_bsize != BSIZE) {
1018         Log("SuperBlk: Cluster size not %d; run vfsck\n", BSIZE);
1019         goto out;
1020     }
1021     fmax = super.fs.s_fsize;    /* first invalid blk num */
1022     imax = ((ino_t) super.fs.s_isize - (SUPERB + 1)) * INOPB;
1023     if (imax == 0) {
1024         Log("Size check: imax==0!\n");
1025         goto out;
1026     }
1027     if (GetAuxInodeFile(partition, &status) == 0) {
1028         Log("Can't access Aux inode file for partition %s, aborting\n",
1029             partition);
1030         goto out;
1031     }
1032     for (inum = 1; inum <= imax; inum++) {
1033         struct dauxinode *auxp;
1034         if ((auxp = IsAfsInode(inum)) == NULL) {
1035             /* Not an afs inode, keep going */
1036             continue;
1037         }
1038         if ((p = ginode(inum)) == NULL)
1039             continue;
1040         /* deleted/non-existent inode when di_mode == 0 */
1041         if (!p->di_mode)
1042             continue;
1043         info.inodeNumber = (int)inum;
1044         info.byteCount = p->di_size;
1045         info.linkCount = p->di_nlink;
1046         info.u.param[0] = auxp->aux_param1;
1047         info.u.param[1] = auxp->aux_param2;
1048         info.u.param[2] = auxp->aux_param3;
1049         info.u.param[3] = auxp->aux_param4;
1050         if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
1051             continue;
1052         if (inodeFile) {
1053             if (fwrite(&info, sizeof info, 1, inodeFile) != 1) {
1054                 Log("Error writing inode file for partition %s\n", partition);
1055                 goto out;
1056             }
1057         }
1058         ninodes++;
1059     }
1060 #else
1061     /*
1062      * run a few consistency checks of the superblock
1063      * (Cribbed from vfsck)
1064      */
1065 #ifdef AFS_HPUX_ENV
1066 #if defined(FD_FSMAGIC)
1067     if ((sblock.fs_magic != FS_MAGIC) && (sblock.fs_magic != FS_MAGIC_LFN)
1068         && (sblock.fs_magic != FD_FSMAGIC)
1069 #if     defined(AFS_HPUX101_ENV)
1070         && (sblock.fs_magic != FD_FSMAGIC_2)
1071 #endif
1072         ) {
1073 #else
1074     if ((sblock.fs_magic != FS_MAGIC) && (sblock.fs_magic != FS_MAGIC_LFN)) {
1075 #endif
1076         Log("There's something wrong with the superblock for partition %s; bad magic (%d) run vfsck\n", partition, sblock.fs_magic);
1077         goto out;
1078     }
1079     if (sblock.fs_ncg < 1) {
1080         Log("There's something wrong with the superblock for partition %s; NCG OUT OF RANGE (%d) run vfsck\n", partition, sblock.fs_ncg);
1081         goto out;
1082     }
1083     if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG) {
1084         Log("There's something wrong with the superblock for partition %s; CPG OUT OF RANGE (%d) run vfsck\n", partition, sblock.fs_cpg);
1085         goto out;
1086     }
1087     if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl
1088         || (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) {
1089         Log("There's something wrong with the superblock for partition %s; NCYL LESS THAN NCG*CPG run vfsck\n", partition);
1090         goto out;
1091     }
1092     if (sblock.fs_sbsize > SBSIZE) {
1093         Log("There's something wrong with the superblock for partition %s; bsize too large (%d vs. %d) run vfsck\n", partition, sblock.fs_sbsize, sblock.fs_bsize);
1094         goto out;
1095     }
1096 #else
1097     if ((super.fs.fs_magic != FS_MAGIC)
1098         || (super.fs.fs_ncg < 1)
1099 #if     defined(AFS_SUN_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1100         || (super.fs.fs_cpg < 1)
1101 #else
1102         || (super.fs.fs_cpg < 1 || super.fs.fs_cpg > MAXCPG)
1103 #endif
1104         || (super.fs.fs_ncg * super.fs.fs_cpg < super.fs.fs_ncyl
1105             || (super.fs.fs_ncg - 1) * super.fs.fs_cpg >= super.fs.fs_ncyl)
1106         || (super.fs.fs_sbsize > SBSIZE)) {
1107         Log("There's something wrong with the superblock for partition %s; run vfsck\n", partition);
1108         goto out;
1109     }
1110 #endif /* AFS_HPUX_ENV */
1111
1112 #ifdef AFS_HPUX_ENV
1113     bufsize = sblock.fs_ipg * sizeof(struct dinode);
1114 #else
1115     bufsize = super.fs.fs_ipg * sizeof(struct dinode);
1116 #endif /* AFS_HPUX_ENV */
1117     inodes = (struct dinode *)malloc(bufsize);
1118     einodes = (struct dinode *)(((char *)inodes) + bufsize);
1119     if (inodes == NULL) {
1120         Log("Unable to allocate enough memory to scan inodes; help!\n");
1121         goto out;
1122     }
1123     Log("Scanning inodes on device %s...\n", rdev);
1124 #ifdef AFS_HPUX_ENV
1125     for (c = 0; c < sblock.fs_ncg; c++) {
1126         i = c * sblock.fs_ipg;
1127         e = i + sblock.fs_ipg;
1128 #if     defined(AFS_HPUX102_ENV)
1129         if (afs_lseek(pfd, dbtoo(fsbtodb(&sblock, itod(&sblock, i))), L_SET) ==
1130             -1) {
1131 #else
1132         if (afs_lseek(pfd, dbtob(fsbtodb(&sblock, itod(&sblock, i))), L_SET) ==
1133             -1) {
1134 #endif
1135 #else
1136     for (c = 0; c < super.fs.fs_ncg; c++) {
1137         daddr_t dblk1;
1138 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
1139         daddr_t f1;
1140 #if defined(AFS_DARWIN_ENV)
1141 #define offset_t off_t
1142 #define llseek lseek
1143 #endif
1144         offset_t off;
1145 #endif /* AFS_SUN5_ENV */
1146         i = c * super.fs.fs_ipg;
1147         e = i + super.fs.fs_ipg;
1148 #ifdef  AFS_OSF_ENV
1149         dblk1 = fsbtodb(&super.fs, itod(&super.fs, i));
1150         if (afs_lseek(pfd, (off_t) ((off_t) dblk1 * DEV_BSIZE), L_SET) == -1) {
1151 #else
1152 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
1153         f1 = fsbtodb(&super.fs, itod(&super.fs, i));
1154         off = (offset_t) f1 << DEV_BSHIFT;
1155         if (llseek(pfd, off, L_SET) == -1) {
1156 #else
1157         if (afs_lseek(pfd, dbtob(fsbtodb(&super.fs, itod(&super.fs, i))), L_SET)
1158             == -1) {
1159 #endif /* AFS_SUN5_ENV */
1160 #endif /* AFS_OSF_ENV */
1161 #endif /* AFS_HPUX_ENV */
1162             Log("Error reading inodes for partition %s; run vfsck\n",
1163                 partition);
1164             goto out;
1165         }
1166         while (i < e) {
1167             if (!forceR) {
1168                 if (read(pfd, inodes, bufsize) != bufsize) {
1169                     Log("Error reading inodes for partition %s; run vfsck\n",
1170                         partition);
1171                     goto out;
1172                 }
1173             } else {
1174                 register int bj, bk;
1175                 dptr = inodes;
1176                 for (bj = bk = 0; bj < bufsize; bj = bj + 512, bk++) {
1177                     if ((code = read(pfd, dptr, 512)) != 512) {
1178                         Log("Error reading inode %d? for partition %s (errno = %d); run vfsck\n", bk + i, partition, errno);
1179                         if (afs_lseek(pfd, 512, L_SET) == -1) {
1180                             Log("Lseek failed\n");
1181                             goto out;
1182                         }
1183                         dptr->di_mode = 0;
1184                         dptr++;
1185                         dptr->di_mode = 0;
1186                         dptr++;
1187                         dptr->di_mode = 0;
1188                         dptr++;
1189                         dptr->di_mode = 0;
1190                         dptr++;
1191                     } else
1192                         dptr += 4;
1193                 }
1194             }
1195             for (p = inodes; p < einodes && i < e; i++, p++) {
1196 #ifdef notdef
1197                 Log("Ino=%d, v1=%x, v2=%x, v3=%x, mode=%x size=%d, lcnt=%d\n",
1198                     i, p->di_vicep1, p->di_vicep2, p->di_vicep3, p->di_mode,
1199                     p->di_size, p->di_nlink);
1200                 printf
1201                     ("Ino=%d, v1=%x, v2=%x, v3=%x, mode=%x size=%d, lcnt=%d\n",
1202                      i, p->di_vicep1, p->di_vicep2, p->di_vicep3, p->di_mode,
1203                      p->di_size, p->di_nlink);
1204 #endif
1205 #ifdef AFS_OSF_ENV
1206 #ifdef AFS_3DISPARES
1207                 /* Check to see if this inode is a pre-"OSF1 4.0D" inode */
1208                 if ((p->di_uid || p->di_gid)
1209                     && !(p->di_flags & (IC_XUID | IC_XGID))) {
1210                     Log("Found unconverted inode %d: Use 'fs_conv_dux40D convert' on partition %s\n", i, partition);
1211                     goto out;
1212                 }
1213 #else
1214                 assert(0);      /* define AFS_3DISPARES in param.h */
1215 #endif
1216 #endif
1217 #if     defined(AFS_SUN56_ENV)
1218                 /* if this is a pre-sol2.6 unconverted inode, bail out */
1219                 {
1220                     afs_uint32 p1, p2, p3, p4;
1221                     int p5;
1222                     quad *q;
1223
1224                     q = (quad *) & (p->di_ic.ic_lsize);
1225                     p1 = p->di_gen;
1226                     p2 = p->di_ic.ic_flags;
1227                     p3 = q->val[0];
1228                     p4 = p->di_ic.ic_uid;
1229                     p5 = p->di_ic.ic_gid;
1230
1231                     if ((p2 || p3) && !p4 && (p5 == -2)) {
1232                         Log("Found unconverted inode %d\n", i);
1233                         Log("You should run the AFS file conversion utility\n");
1234                         goto out;
1235                     }
1236                 }
1237 #endif
1238                 if (IS_DVICEMAGIC(p) && (p->di_mode & IFMT) == IFREG) {
1239                     afs_uint32 p2 = p->di_vicep2, p3 = DI_VICEP3(p);
1240
1241                     info.u.param[0] = p->di_vicep1;
1242 #ifdef  AFS_3DISPARES
1243                     if (((p2 >> 3) == INODESPECIAL) && (p2 & 0x3)) {
1244                         info.u.param[1] = INODESPECIAL;
1245                         info.u.param[2] = p3;
1246                         info.u.param[3] = p2 & 0x3;
1247                     } else {
1248                         info.u.param[1] = ((p2 >> 27) << 16) + (p3 & 0xffff);
1249                         info.u.param[2] = (p2 & 0x3fffff);
1250                         info.u.param[3] =
1251                             (((p2 >> 22) & 0x1f) << 16) + (p3 >> 16);
1252                     }
1253 #else
1254                     info.u.param[1] = p->di_vicep2;
1255                     info.u.param[2] = DI_VICEP3(p);
1256                     info.u.param[3] = p->di_vicep4;
1257 #endif
1258                     info.inodeNumber = i;
1259                     info.byteCount = p->di_size;
1260                     info.linkCount = p->di_nlink;
1261                     if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
1262                         continue;
1263                     if (inodeFile) {
1264                         if (fwrite(&info, sizeof info, 1, inodeFile) != 1) {
1265                             Log("Error writing inode file for partition %s\n",
1266                                 partition);
1267                             goto out;
1268                         }
1269                     }
1270                     ninodes++;
1271                 }
1272             }
1273         }
1274     }
1275     if (inodes)
1276         free(inodes);
1277 #endif
1278     if (inodeFile) {
1279         if (fflush(inodeFile) == EOF) {
1280             Log("Unable to successfully flush inode file for %s\n", partition);
1281             err = -2;
1282             goto out1;
1283         }
1284         if (fsync(fileno(inodeFile)) == -1) {
1285             Log("Unable to successfully fsync inode file for %s\n", partition);
1286             err = -2;
1287             goto out1;
1288         }
1289         if (fclose(inodeFile) == EOF) {
1290             Log("Unable to successfully close inode file for %s\n", partition);
1291             err = -2;
1292             goto out1;
1293         }
1294         
1295         /*
1296          * Paranoia:  check that the file is really the right size
1297          */
1298         if (stat(resultFile, &status) == -1) {
1299             Log("Unable to successfully stat inode file for %s\n", partition);
1300             err = -2;
1301             goto out1;
1302         }
1303         if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
1304             Log("Wrong size (%d instead of %d) in inode file for %s\n",
1305                 status.st_size, ninodes * sizeof(struct ViceInodeInfo),
1306                 partition);
1307             err = -2;
1308             goto out1;
1309         }
1310     }
1311     close(pfd);
1312     return 0;
1313
1314   out:
1315     err = -1;
1316   out1:
1317     close(pfd);
1318     if (inodeFile)
1319         fclose(inodeFile);
1320     if (inodes)
1321         free(inodes);
1322     return err;
1323 }
1324 #endif /* !AFS_SGI_ENV */
1325 #endif /* !AFS_AIX31_ENV       */
1326
1327 #ifdef AFS_DARWIN_ENV
1328 #undef dbtob
1329 #define dbtob(db) ((unsigned)(db) << DEV_BSHIFT)
1330 #endif
1331
1332 int
1333 bread(int fd, char *buf, daddr_t blk, afs_int32 size)
1334 {
1335 #ifdef  AFS_AIX_ENV
1336 #ifdef  AFS_AIX41_ENV
1337     offset_t off = (offset_t) blk << FSBSHIFT;
1338     if (llseek(fd, off, 0) < 0) {
1339         Log("Unable to seek to offset %llu for block %u\n", off, blk);
1340         return -1;
1341     }
1342 #else /* AFS_AIX41_ENV */
1343     if (afs_lseek(fd, blk * Bsize, 0) < 0) {
1344         Log("Unable to seek to offset %u for block %u\n", blk * Bsize, blk);
1345     }
1346 #endif /* AFS_AIX41_ENV */
1347 #else
1348     if (afs_lseek(fd, (off_t) dbtob(blk), L_SET) < 0) {
1349         Log("Unable to seek to offset %u for block %u\n", dbtob(blk), blk);
1350     }
1351 #endif
1352     if (read(fd, buf, size) != size) {
1353         Log("Unable to read block %d, partition %s\n", blk, partition);
1354         return -1;
1355     }
1356     return 0;
1357 }
1358
1359 #endif /* AFS_LINUX20_ENV */
1360 static afs_int32
1361 convertVolumeInfo(int fdr, int fdw, afs_uint32 vid)
1362 {
1363     struct VolumeDiskData vd;
1364     char *p;
1365
1366     if (read(fdr, &vd, sizeof(struct VolumeDiskData)) !=
1367         sizeof(struct VolumeDiskData)) {
1368         Log("1 convertiVolumeInfo: read failed for %lu with code %d\n", vid,
1369             errno);
1370         return -1;
1371     }
1372     vd.restoredFromId = vd.id;  /* remember the RO volume here */
1373     vd.cloneId = vd.id;
1374     vd.id = vd.parentId;
1375     vd.type = RWVOL;
1376     vd.dontSalvage = 0;
1377     vd.inUse = 0;
1378     vd.uniquifier += 5000;      /* just in case there are still file copies 
1379                                    from the old RW volume around */
1380
1381     p = strrchr(vd.name, '.');
1382     if (p && !strcmp(p, ".readonly")) {
1383         memset(p, 0, 9);
1384     }
1385
1386     if (write(fdw, &vd, sizeof(struct VolumeDiskData)) !=
1387         sizeof(struct VolumeDiskData)) {
1388         Log("1 convertiVolumeInfo: write failed for %lu with code %d\n", vid,
1389             errno);
1390         return -1;
1391     }
1392     return 0;
1393 }
1394
1395 struct specino {
1396     afs_int32 inodeType;
1397     Inode inodeNumber;
1398     Inode ninodeNumber;
1399 };
1400
1401
1402 int
1403 UpdateThisVolume(struct ViceInodeInfo *inodeinfo, VolumeId singleVolumeNumber, 
1404                  struct specino *specinos)
1405 {
1406     struct dinode *p;
1407     if ((inodeinfo->u.vnode.vnodeNumber == INODESPECIAL) &&
1408         (inodeinfo->u.vnode.volumeId == singleVolumeNumber)) {
1409         specinos[inodeinfo->u.special.type].inodeNumber = 
1410             inodeinfo->inodeNumber;
1411     }
1412     return 0; /* We aren't using a result file, we're caching */
1413 }
1414
1415 static char *
1416 getDevName(char *pbuffer, char *wpath)
1417 {
1418     char pbuf[128], *ptr;
1419     strcpy(pbuf, pbuffer);
1420     ptr = (char *)strrchr(pbuf, '/');
1421     if (ptr) {
1422         *ptr = '\0';
1423         strcpy(wpath, pbuf);
1424     } else
1425         return NULL;
1426     ptr = (char *)strrchr(pbuffer, '/');
1427     if (ptr) {
1428         strcpy(pbuffer, ptr + 1);
1429         return pbuffer;
1430     } else
1431         return NULL;
1432 }
1433
1434 #ifdef FSSYNC_BUILD_CLIENT
1435 int
1436 inode_ConvertROtoRWvolume(char *pname, afs_uint32 volumeId)
1437 {
1438     char dir_name[512], oldpath[512], newpath[512];
1439     char volname[20];
1440     char headername[16];
1441     char *name;
1442     int fd, err, forcep, len, j, code;
1443     struct dirent *dp;
1444     struct DiskPartition64 *partP;
1445     struct ViceInodeInfo info;
1446     struct VolumeDiskHeader h;
1447     IHandle_t *ih, *ih2;
1448     FdHandle_t *fdP, *fdP2;
1449     char wpath[100];
1450     char tmpDevName[100];
1451     char buffer[128];
1452     struct specino specinos[VI_LINKTABLE+1];
1453     Inode nearInode = 0;
1454
1455     memset(&specinos, 0, sizeof(specinos));
1456            
1457     (void)afs_snprintf(headername, sizeof headername, VFORMAT, afs_cast_uint32(volumeId));
1458     (void)afs_snprintf(oldpath, sizeof oldpath, "%s/%s", pname, headername);
1459     fd = open(oldpath, O_RDONLY);
1460     if (fd < 0) {
1461         Log("1 inode_ConvertROtoRWvolume: Couldn't open header for RO-volume %lu.\n", volumeId);
1462         return ENOENT;
1463     }
1464     if (read(fd, &h, sizeof(h)) != sizeof(h)) {
1465         Log("1 inode_ConvertROtoRWvolume: Couldn't read header for RO-volume %lu.\n", volumeId);
1466         close(fd);
1467         return EIO;
1468     }
1469     close(fd);
1470     FSYNC_VolOp(volumeId, pname, FSYNC_VOL_BREAKCBKS, 0, NULL);
1471
1472     /* now do the work */
1473            
1474     for (partP = DiskPartitionList; partP && strcmp(partP->name, pname);
1475          partP = partP->next);
1476     if (!partP) {
1477         Log("1 inode_ConvertROtoRWvolume: Couldn't find DiskPartition for %s\n", pname);
1478         return EIO;
1479     }
1480
1481     strcpy(tmpDevName, partP->devName);
1482     name = getDevName(tmpDevName, wpath);
1483
1484     if ((err = ListViceInodes(name, VPartitionPath(partP), 
1485                               NULL, UpdateThisVolume, volumeId, 
1486                               &forcep, 0, wpath, &specinos)) < 0)
1487     {
1488         Log("1 inode_ConvertROtoRWvolume: Couldn't get special inodes\n");
1489         return EIO;
1490     }
1491            
1492 #if defined(NEARINODE_HINT)
1493     nearInodeHash(volumeId, nearInode);
1494     nearInode %= partP->f_files;
1495 #endif
1496
1497     for (j = VI_VOLINFO; j < VI_LINKTABLE+1; j++) {
1498         if (specinos[j].inodeNumber > 0) {
1499             specinos[j].ninodeNumber = 
1500                 IH_CREATE(NULL, partP->device, VPartitionPath(partP),
1501                           nearInode, h.parent, INODESPECIAL, j, h.parent);
1502             IH_INIT(ih, partP->device, volumeId, 
1503                     specinos[j].inodeNumber);
1504             fdP = IH_OPEN(ih);
1505             if (!fdP) {
1506                 Log("1 inode_ConvertROtoRWvolume: Couldn't find special inode %d for %d\n", j, volumeId); 
1507                 return -1;
1508             }
1509             
1510             IH_INIT(ih2, partP->device, h.parent, specinos[j].ninodeNumber);
1511             fdP2 = IH_OPEN(ih2); 
1512             if (!fdP2) { 
1513                 Log("1 inode_ConvertROtoRWvolume: Couldn't find special inode %d for %d\n", j, h.parent);  
1514                 return -1; 
1515             } 
1516             
1517             if (j == VI_VOLINFO)
1518                 convertVolumeInfo(fdP->fd_fd, fdP2->fd_fd, ih2->ih_vid);
1519             else {
1520                 while (1) {
1521                     len = read(fdP->fd_fd, buffer, sizeof(buffer));
1522                     if (len < 0)
1523                         return errno;
1524                     if (len == 0)
1525                         break;
1526                     code = write(fdP2->fd_fd, buffer, len);
1527                     if (code != len)
1528                         return -1;
1529                 }
1530             }
1531                 
1532             FDH_CLOSE(fdP);
1533             FDH_CLOSE(fdP2);
1534             IH_RELEASE(ih);
1535             IH_RELEASE(ih2);
1536         }
1537     }
1538    
1539     h.id = h.parent;
1540 #ifdef AFS_64BIT_IOPS_ENV
1541     h.volumeInfo_lo = (afs_int32)specinos[VI_VOLINFO].ninodeNumber & 0xffffffff;
1542     h.volumeInfo_hi = (afs_int32)(specinos[VI_VOLINFO].ninodeNumber >> 32) && 0xffffffff;
1543     h.smallVnodeIndex_lo = (afs_int32)specinos[VI_SMALLINDEX].ninodeNumber & 0xffffffff;
1544     h.smallVnodeIndex_hi = (afs_int32)(specinos[VI_SMALLINDEX].ninodeNumber >> 32) & 0xffffffff;
1545     h.largeVnodeIndex_lo = (afs_int32)specinos[VI_LARGEINDEX].ninodeNumber & 0xffffffff;
1546     h.largeVnodeIndex_hi = (afs_int32)(specinos[VI_LARGEINDEX].ninodeNumber >> 32) & 0xffffffff;
1547     if (specinos[VI_LINKTABLE].ninodeNumber) {
1548         h.linkTable_lo = (afs_int32)specinos[VI_LINKTABLE].ninodeNumber & 0xffffffff;
1549         h.linkTable_hi = (afs_int32)specinos[VI_LINKTABLE].ninodeNumber & 0xffffffff;
1550     }
1551 #else
1552     h.volumeInfo_lo = specinos[VI_VOLINFO].ninodeNumber;
1553     h.smallVnodeIndex_lo = specinos[VI_SMALLINDEX].ninodeNumber;
1554     h.largeVnodeIndex_lo = specinos[VI_LARGEINDEX].ninodeNumber;
1555     if (specinos[VI_LINKTABLE].ninodeNumber) {
1556         h.linkTable_lo = specinos[VI_LINKTABLE].ninodeNumber;
1557     }
1558 #endif
1559
1560     (void)afs_snprintf(headername, sizeof headername, VFORMAT, afs_cast_uint32(h.id));
1561     (void)afs_snprintf(newpath, sizeof newpath, "%s/%s", pname, headername);
1562     fd = open(newpath, O_CREAT | O_EXCL | O_RDWR, 0644);
1563     if (fd < 0) {
1564         Log("1 inode_ConvertROtoRWvolume: Couldn't create header for RW-volume %lu.\n", h.id);
1565         return EIO;
1566     }
1567     if (write(fd, &h, sizeof(h)) != sizeof(h)) {
1568         Log("1 inode_ConvertROtoRWvolume: Couldn't write header for RW-volume %lu.\n", h.id);
1569         close(fd);
1570         return EIO;
1571     }
1572     close(fd);
1573     if (unlink(oldpath) < 0) {
1574         Log("1 inode_ConvertROtoRWvolume: Couldn't unlink RO header, error = %d\n", errno);
1575     }
1576     FSYNC_VolOp(volumeId, pname, FSYNC_VOL_DONE, 0, NULL);
1577     FSYNC_VolOp(h.id, pname, FSYNC_VOL_ON, 0, NULL);
1578     return 0;
1579 }
1580 #endif /* FSSYNC_BUILD_CLIENT */
1581 #endif /* AFS_NAMEI_ENV */