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