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