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