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