Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / vol / listinodes.c
blobfcbdb2a23f981810612621de9c54409d5654fb59
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
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 */
12 System: VICE-TWO
13 Module: listinodes.c
14 Institution: The Information Technology Center, Carnegie-Mellon University
18 #define ITC /* Required by inode.h */
20 #include <afsconfig.h>
21 #include <afs/param.h>
23 #include <string.h>
26 #ifndef AFS_NAMEI_ENV
27 #if defined(AFS_LINUX20_ENV) || defined(AFS_SUN4_ENV)
28 /* ListViceInodes
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.
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)
40 Log("ListViceInodes not implemented for this platform!\n");
41 return -1;
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"
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@*/
137 /* Notice: parts of this module have been cribbed from vfsck.c */
139 #define ROOTINODE 2
140 static char *partition;
141 int Testing=0;
142 int pfd;
144 #ifdef AFS_AIX32_ENV
145 #include <jfs/filsys.h>
147 #ifndef FSBSIZE
148 #define FSBSIZE (4096) /* filesystem block size */
149 #define FSBSHIFT (12) /* log2(FSBSIZE) */
150 #define FSBMASK (FSBSIZE - 1) /* FSBSIZE mask */
152 #define MIN_FSIZE DISKMAP_B /* minimum fs size (FSblocks) */
153 #define LAST_RSVD_I 15 /* last reserved inode */
154 #endif
156 #ifndef INOPB
158 * This will hopefully eventually make it into the system include files
160 #define INOPB (FSBSIZE / sizeof (struct dinode))
161 #endif
163 #ifdef AFS_AIX41_ENV
164 int fragsize;
165 int iagsize;
166 int ag512;
167 int agblocks;
168 #endif /* AFS_AIX41_ENV */
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
176 * itoo - inode number to offset within disk block
178 #undef itoo
179 #define itoo(x) (int) ((unsigned)(x) % INOPB)
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 */
185 static struct superblock fs;
186 struct dinode *ginode();
190 ListViceInodes(char *devname, char *mountedOn, FILE *inodeFile,
191 int (*judgeInode) (), afs_uint32 judgeParam, int *forcep, int forceR,
192 char *wpath, void *rock)
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;
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);
210 partition = mountedOn;
211 sprintf(dev, "/dev/%s", devname);
212 sprintf(rdev, "/dev/r%s", devname);
214 if (stat(mountedOn, &root_inode) < 0) {
215 Log("cannot stat: %s\n", mountedOn);
216 return -1;
219 if (root_inode.st_ino != ROOTDIR_I) {
220 Log("%s is not root of a filesystem\n", mountedOn);
221 return -1;
226 * done with the superblock, now try to read the raw device.
228 if (ReadSuper(&fs, dev) < 0)
229 return -1;
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;
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;
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;
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;
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
264 #endif
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 */
273 fmax = fs.s_fsize / (FSBSIZE / 512); /* first invalid blk num */
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;
282 * calculate the maximum number of inodes possible
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 */
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.
298 osi_Assert(p = ginode(LAST_RSVD_I));
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);
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;
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;
319 if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
320 continue;
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;
328 ++ninodes;
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;
337 if (fsync(fileno(inodeFile)) == -1) {
338 Log("Unable to successfully fsync inode file for %s\n", partition);
339 err = -2;
340 goto out1;
344 * Paranoia: check that the file is really the right size
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;
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;
359 close(pfd);
360 return 0;
362 out:
363 err = -1;
364 out1:
365 if (pfd >= 0)
366 close(pfd);
368 return err;
371 /* Read in the superblock for devName */
373 ReadSuper(struct superblock *fs, char *devName)
375 int pfd;
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;
383 if (bread(pfd, fs, SUPER_B, sizeof(struct superblock)) < 0) {
384 Log("Unable to read superblock on %s.\n", devName);
385 return -1;
387 close(pfd);
388 return (0);
391 #ifdef AFS_AIX42_ENV
392 /* IsBigFilesFileSystem returns 1 if it's a big files filesystem, 0 otherwise. */
394 IsBigFilesFileSystem(struct superblock *sb)
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;
403 #endif
405 struct dinode *
406 ginode(inum)
408 int ag;
409 daddr_t pblk;
410 struct dinode *dp;
411 static char buf[FSBSIZE];
412 static daddr_t last_blk = -1;
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 */
431 if (last_blk != pblk) {
432 if (bread(pfd, buf, pblk, sizeof(buf)) < 0) {
433 last_blk = -1;
434 return 0;
436 last_blk = pblk;
439 dp = (struct dinode *)buf;
440 dp += itoo(inum);
441 return (dp);
444 #else /* !AFS_AIX31_ENV */
446 #if defined(AFS_SGI_ENV)
448 /* libefs.h includes <assert.h>, which we don't want */
449 #define __ASSERT_H__
451 #ifdef AFS_SGI_XFS_IOPS_ENV
452 #include <dirent.h>
453 #include <afs/xfsattrs.h>
454 /* xfs_ListViceInodes
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.
472 /* xfs_VerifyInode
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.
479 xfs_VerifyInode(char *dir, uint64_t pino, char *name, i_list_inode_t * info,
480 int *rename)
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 int tag;
490 afs_ino_str_t stmp;
492 *rename = 0;
493 (void)sprintf(path, "%s/%s", dir, name);
494 /* Verify uid and gid fields */
495 if (info->ili_magic != XFS_VICEMAGIC) {
496 Log("%s magic for %s/%s (inode %s) from %d to %d\n",
497 Testing ? "Would have changed" : "Changing", dir, name,
498 PrintInode(stmp, info->ili_info.inodeNumber), info->ili_magic,
499 XFS_VICEMAGIC);
500 if (!Testing)
501 update_chown = 1;
504 vno = info->ili_info.param[0];
505 if (info->ili_vno != AFS_XFS_VNO_CLIP(vno)) {
506 Log("%s volume id for %s/%s (inode %s) from %d to %d\n",
507 Testing ? "Would have changed" : "Changing", dir, name,
508 PrintInode(stmp, info->ili_info.inodeNumber), info->ili_vno,
509 AFS_XFS_VNO_CLIP(vno));
510 if (!Testing)
511 update_chown = 1;
514 if (update_chown) {
515 if (chown(path, AFS_XFS_VNO_CLIP(vno), XFS_VICEMAGIC) < 0) {
516 Log("Can't chown %s to uid=%d, gid=0x%x\n", path,
517 AFS_XFS_VNO_CLIP(vno), XFS_VICEMAGIC);
518 retCode = -1;
522 /* Check Parent inode number. */
523 if (info->ili_pino != pino) {
524 afs_ino_str_t sino, sipino, spino;
525 (void)PrintInode(sino, info->ili_info.inodeNumber);
526 (void)PrintInode(sipino, info->ili_pino);
527 (void)PrintInode(spino, pino);
528 Log("%s parent ino for %s (inode %s) from %s to %s.\n",
529 Testing ? "Would have changed" : "Changing", path, sino, sipino,
530 spino);
531 if (!Testing)
532 update_pino = 1;
535 /* Verify the file name. */
536 (void)strcpy(tmpName, ".");
537 (void)strcat(tmpName, int_to_base64(stmp, info->ili_info.param[2]));
538 if (strncmp(name, tmpName, strlen(tmpName))) {
539 Log("%s name %s (inode %s) in directory %s, unique=%d, tag=%d\n",
540 Testing ? "Would have returned bad" : "Bad", name,
541 PrintInode(stmp, info->ili_info.inodeNumber), dir,
542 info->ili_info.param[2], info->ili_tag);
543 if (!Testing)
544 *rename = 1;
547 if (!*rename) {
548 /* update the tag? */
549 (void)strcat(tmpName, ".");
550 (void)strcat(tmpName, int_to_base64(stmp, info->ili_tag));
551 if (strcmp(name, tmpName)) {
552 char *p;
553 (void)strcpy(tmpName, name);
554 p = strchr(tmpName + 1, '.');
555 if (!p) {
556 Log("No tag found on name %s (inode %s)in directory, %s.\n",
557 name, PrintInode(stmp, info->ili_info.inodeNumber), dir,
558 Testing ? "would have renamed" : "will rename");
559 if (!Testing)
560 *rename = 1;
561 } else {
562 tag = base64_to_int(p + 1);
563 Log("%s the tag for %s (inode %s) from %d to %d.\n",
564 Testing ? "Would have changed" : "Will change", path,
565 PrintInode(stmp, info->ili_info.inodeNumber), dir, tag,
566 info->ili_tag);
567 if (!Testing)
568 update_tag = 1;
573 if (update_pino || update_tag) {
574 afs_xfs_attr_t attrs;
575 int length;
577 length = SIZEOF_XFS_ATTR_T;
578 if (attr_get(path, AFS_XFS_ATTR, (char *)&attrs, &length, ATTR_ROOT) <
579 0) {
580 Log("Can't get AFS attribute for %s\n", path);
581 return -1;
583 if (update_pino)
584 attrs.at_pino = pino;
585 if (update_tag)
586 attrs.at_tag = tag;
587 if (attr_set
588 (path, AFS_XFS_ATTR, (char *)&attrs, length,
589 ATTR_ROOT | ATTR_REPLACE) < 0) {
590 Log("Can't set AFS attribute into %s\n", path);
591 retCode = -1;
595 return retCode;
598 typedef struct {
599 int uniq;
600 char name[28];
601 } xfs_Rename_t;
604 xfs_RenameFiles(char *dir, xfs_Rename_t * renames, int n_renames)
606 int i, j;
607 char opath[128], nbase[128], npath[128];
608 afs_xfs_attr_t attrs;
609 int length = SIZEOF_XFS_ATTR_T;
610 b64_string_t stmp;
611 int tag;
612 int fd;
614 for (i = 0; i < n_renames; i++) {
615 (void)sprintf(opath, "%s/%s", dir, renames[i].name);
616 (void)sprintf(nbase, "%s/.%s", dir,
617 int_to_base64(stmp, renames[i].uniq));
618 for (tag = 2, j = 0; j < 64; tag++, j++) {
619 (void)sprintf(npath, "%s.%s", nbase, int_to_base64(stmp, tag));
620 fd = afs_open(npath, O_CREAT | O_EXCL | O_RDWR, 0);
621 if (fd > 0) {
622 close(fd);
623 break;
626 if (j != 64) {
627 Log("Can't find a new name for %s\n", opath);
628 return -1;
630 if (rename(opath, npath) < 0) {
631 Log("Can't rename %s to %s\n", opath, npath);
632 return -1;
634 Log("Renamed %s to %s\n", opath, npath);
635 return 0;
641 xfs_ListViceInodes(char *devname, char *mountedOn, FILE *inodeFile,
642 int (*judgeInode) (), afs_uint32 judgeParam, int *forcep,
643 int forceR, char *wpath, void *rock)
645 i_list_inode_t info;
646 int info_size = sizeof(i_list_inode_t);
647 int fd;
648 DIR *top_dirp;
649 dirent64_t *top_direntp;
650 DIR *vol_dirp;
651 dirent64_t *vol_direntp;
652 struct stat64 sdirbuf;
653 struct stat64 sfilebuf;
654 afs_xfs_attr_t attrs;
655 afs_xfs_dattr_t dattrs;
656 int length;
657 char vol_dirname[1024];
658 int ninodes = 0;
659 int code = 0;
660 xfs_Rename_t *renames = (xfs_Rename_t *) 0;
661 int rename;
662 #define N_RENAME_STEP 64
663 int n_renames = 0;
664 int n_avail = 0;
665 uint64_t pino;
666 struct stat status;
667 int errors = 0;
669 *forcep = 0;
671 if (stat64(mountedOn, &sdirbuf) < 0) {
672 perror("xfs_ListViceInodes: stat64");
673 return -1;
676 if ((top_dirp = opendir(mountedOn)) == NULL) {
677 Log("Can't open directory %s to read inodes.\n", mountedOn);
678 return -1;
681 while (top_direntp = readdir64(top_dirp)) {
682 /* Only descend directories with the AFSDIR attribute set.
683 * Could also verify the contents of the atribute, but currently
684 * they are not used.
685 * Performance could be improved for single volume salvages by
686 * only going through the directory containing the volume's inodes.
687 * But I'm being complete as a first pass.
689 (void)sprintf(vol_dirname, "%s/%s", mountedOn, top_direntp->d_name);
690 length = SIZEOF_XFS_DATTR_T;
691 if (attr_get
692 (vol_dirname, AFS_XFS_DATTR, (char *)&dattrs, &length, ATTR_ROOT))
693 continue;
695 if ((vol_dirp = opendir(vol_dirname)) == NULL) {
696 if (errno == ENOTDIR)
697 continue;
698 Log("Can't open directory %s to read inodes.\n", vol_dirname);
699 goto err1_exit;
702 pino = top_direntp->d_ino;
703 n_renames = 0;
704 while (vol_direntp = readdir64(vol_dirp)) {
705 if (vol_direntp->d_name[1] == '\0'
706 || vol_direntp->d_name[1] == '.')
707 continue;
709 info.ili_version = AFS_XFS_ILI_VERSION;
710 info_size = sizeof(i_list_inode_t);
711 code =
712 ilistinode64(sdirbuf.st_dev, vol_direntp->d_ino, &info,
713 &info_size);
714 if (code) {
715 /* Where possible, give more explicit messages. */
716 switch (errno) {
717 case ENXIO:
718 case ENOSYS:
719 Log("%s (device id %d) is not on an XFS filesystem.\n",
720 vol_dirname, sdirbuf.st_dev);
721 goto err1_exit;
722 break;
723 case EINVAL:
724 case E2BIG:
725 if (info_size != sizeof(i_list_inode_t)
726 || info.ili_version != AFS_XFS_ILI_VERSION) {
727 Log("Version skew between kernel and salvager.\n");
728 goto err1_exit;
730 break;
732 /* Continue, so we collect all the errors in the first pass. */
733 Log("Error listing inode named %s/%s: %s\n", vol_dirname,
734 vol_direntp->d_name, strerror(errno));
735 errors++;
736 continue;
739 if (info.ili_attr_version != AFS_XFS_ATTR_VERS) {
740 Log("Unrecognized XFS attribute version %d in %s/%s. Upgrade salvager\n", info.ili_attr_version, vol_dirname, vol_direntp->d_name);
741 goto err1_exit;
744 if (judgeInode && (*judgeInode) (&info.ili_info, judgeParam, rock) == 0)
745 continue;
747 rename = 0;
748 if (xfs_VerifyInode
749 (vol_dirname, pino, vol_direntp->d_name, &info,
750 &rename) < 0) {
751 errors++;
754 if (rename) {
755 /* Add this name to the list of items to rename. */
756 if (n_renames >= n_avail) {
757 n_avail += N_RENAME_STEP;
758 if (n_avail == N_RENAME_STEP)
759 renames = (xfs_Rename_t *)
760 malloc(n_avail * sizeof(xfs_Rename_t));
761 else
762 renames = (xfs_Rename_t *)
763 realloc((char *)renames,
764 n_avail * sizeof(xfs_Rename_t));
765 if (!renames) {
766 Log("Can't %salloc %lu bytes for rename list.\n",
767 (n_avail == N_RENAME_STEP) ? "m" : "re",
768 n_avail * sizeof(xfs_Rename_t));
769 goto err1_exit;
772 (void)strcpy(renames[n_renames].name, vol_direntp->d_name);
773 renames[n_renames].uniq = info.ili_info.param[2];
774 n_renames++;
777 if (inodeFile) {
778 if (fwrite
779 (&info.ili_info, sizeof(vice_inode_info_t), 1, inodeFile)
780 != 1) {
781 Log("Error writing inode file for partition %s\n", mountedOn);
782 goto err1_exit;
785 ninodes++;
787 } /* end while vol_direntp */
789 closedir(vol_dirp);
790 vol_dirp = (DIR *) 0;
791 if (n_renames) {
792 Log("Renaming files.\n");
793 if (xfs_RenameFiles(vol_dirname, renames, n_renames) < 0) {
794 goto err1_exit;
799 closedir(top_dirp);
800 if (renames)
801 free((char *)renames);
802 if (inodeFile) {
803 if (fflush(inodeFile) == EOF) {
804 ("Unable to successfully flush inode file for %s\n", mountedOn);
805 return errors ? -1 : -2;
807 if (fsync(fileno(inodeFile)) == -1) {
808 Log("Unable to successfully fsync inode file for %s\n", mountedOn);
809 return errors ? -1 : -2;
812 * Paranoia: check that the file is really the right size
814 if (fstat(fileno(inodeFile), &status) == -1) {
815 Log("Unable to successfully stat inode file for %s\n", partition);
816 return errors ? -1 : -2;
818 if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
819 Log("Wrong size (%d instead of %d) in inode file for %s\n",
820 status.st_size, ninodes * sizeof(struct ViceInodeInfo),
821 partition);
822 return errors ? -1 : -2;
826 if (errors) {
827 Log("Errors encontered listing inodes, not salvaging partition.\n");
828 return -1;
831 return 0;
833 err1_exit:
834 if (vol_dirp)
835 closedir(vol_dirp);
836 if (top_dirp)
837 closedir(top_dirp);
838 if (renames)
839 free((char *)renames);
840 return -1;
843 #endif
846 ListViceInodes(char *devname, char *mountedOn, FILE *inodeFile,
847 int (*judgeInode) (), afs_uint32 judgeParam, int *forcep, int forceR,
848 char *wpath, void *rock)
850 char dev[50], rdev[51];
851 struct stat status;
852 struct efs_dinode *p;
853 struct ViceInodeInfo info;
854 struct stat root_inode;
855 int ninodes = 0, err = 0;
856 struct efs_dinode *dinodeBuf = NULL;
857 int last_cgno;
858 ino_t imax, inum; /* total number of I-nodes in file system */
860 *forcep = 0;
861 sync();
862 sleep(1); /* simulate operator */
863 sync();
864 sleep(1);
865 sync();
866 sleep(1);
868 if (stat(mountedOn, &root_inode) < 0) {
869 Log("cannot stat: %s\n", mountedOn);
870 return -1;
872 #ifdef AFS_SGI_XFS_IOPS_ENV
873 if (!strcmp("xfs", root_inode.st_fstype)) {
874 return xfs_ListViceInodes(devname, mountedOn, inodeFile, judgeInode,
875 judgeParam, forcep, forceR, wpath, rock);
876 } else
877 #endif
879 Log("%s is not root of a filesystem\n", mountedOn);
880 return -1;
884 #else /* AFS_SGI_ENV */
886 #ifdef AFS_HPUX_ENV
887 #define SPERB (MAXBSIZE / sizeof(short))
888 #define MAXNINDIR (MAXBSIZE / sizeof(daddr_t))
890 struct bufarea {
891 struct bufarea *b_next; /* must be first */
892 daddr_t b_bno;
893 int b_size;
894 union {
895 char b_buf[MAXBSIZE]; /* buffer space */
896 short b_lnks[SPERB]; /* link counts */
897 daddr_t b_indir[MAXNINDIR]; /* indirect block */
898 struct fs b_fs; /* super block */
899 struct cg b_cg; /* cylinder group */
900 } b_un;
901 char b_dirty;
903 typedef struct bufarea BUFAREA;
905 BUFAREA sblk;
906 #define sblock sblk.b_un.b_fs
907 #endif /* AFS_HPUX_ENV */
909 extern char *afs_rawname();
911 ListViceInodes(char *devname, char *mountedOn, FILE *inodeFile,
912 int (*judgeInode) (), afs_uint32 judgeParam, int *forcep, int forceR,
913 char *wpath, void *rock)
915 union {
916 #ifdef AFS_AIX_ENV
917 struct filsys fs;
918 char block[BSIZE];
919 #else /* !AFS_AIX_ENV */
920 struct fs fs;
921 char block[SBSIZE];
922 #endif
923 } super;
924 int i, c, e, bufsize, code, err = 0;
925 char dev[50], rdev[100], err1[512], *ptr1;
926 struct dinode *inodes = NULL, *einodes, *dptr;
927 struct stat status;
928 int ninodes = 0;
929 struct dinode *p;
930 struct ViceInodeInfo info;
932 *forcep = 0;
933 partition = mountedOn;
934 sprintf(rdev, "%s/%s", wpath, devname);
935 ptr1 = afs_rawname(rdev);
936 strcpy(rdev, ptr1);
938 sync();
939 /* Bletch: this is terrible; is there a better way to do this? Does this work? vfsck doesn't even sleep!! */
940 #ifdef AFS_AIX_ENV
941 sleep(5); /* Trying a smaller one for aix */
942 #else
943 sleep(10);
944 #endif
946 pfd = afs_open(rdev, O_RDONLY);
947 if (pfd <= 0) {
948 sprintf(err1, "Could not open device %s to get inode list\n", rdev);
949 perror(err1);
950 return -1;
952 #ifdef AFS_AIX_ENV
953 if (bread(pfd, (char *)&super.fs, SUPERB, sizeof super.fs) == -1) {
954 #else
955 #ifdef AFS_HPUX_ENV
956 if (bread(pfd, (char *)&sblock, SBLOCK, SBSIZE) == -1) {
957 #else
958 if (bread(pfd, super.block, SBLOCK, SBSIZE) == -1) {
959 #endif /* AFS_HPUX_ENV */
960 #endif
961 Log("Unable to read superblock, partition %s\n", partition);
962 goto out;
965 #ifdef AFS_AIX_ENV
967 * char *FSlabel(), *fslabel=0;
968 * fslabel = FSlabel(&super.fs);
970 if (super.fs.s_bsize == 0)
971 super.fs.s_bsize = 512;
972 if (super.fs.s_bsize != BSIZE) {
973 Log("SuperBlk: Cluster size not %d; run vfsck\n", BSIZE);
974 goto out;
976 fmax = super.fs.s_fsize; /* first invalid blk num */
977 imax = ((ino_t) super.fs.s_isize - (SUPERB + 1)) * INOPB;
978 if (imax == 0) {
979 Log("Size check: imax==0!\n");
980 goto out;
982 if (GetAuxInodeFile(partition, &status) == 0) {
983 Log("Can't access Aux inode file for partition %s, aborting\n",
984 partition);
985 goto out;
987 for (inum = 1; inum <= imax; inum++) {
988 struct dauxinode *auxp;
989 if ((auxp = IsAfsInode(inum)) == NULL) {
990 /* Not an afs inode, keep going */
991 continue;
993 if ((p = ginode(inum)) == NULL)
994 continue;
995 /* deleted/non-existent inode when di_mode == 0 */
996 if (!p->di_mode)
997 continue;
998 info.inodeNumber = (int)inum;
999 info.byteCount = p->di_size;
1000 info.linkCount = p->di_nlink;
1001 info.u.param[0] = auxp->aux_param1;
1002 info.u.param[1] = auxp->aux_param2;
1003 info.u.param[2] = auxp->aux_param3;
1004 info.u.param[3] = auxp->aux_param4;
1005 if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
1006 continue;
1007 if (inodeFile) {
1008 if (fwrite(&info, sizeof info, 1, inodeFile) != 1) {
1009 Log("Error writing inode file for partition %s\n", partition);
1010 goto out;
1013 ninodes++;
1015 #else
1017 * run a few consistency checks of the superblock
1018 * (Cribbed from vfsck)
1020 #ifdef AFS_HPUX_ENV
1021 #if defined(FD_FSMAGIC)
1022 if ((sblock.fs_magic != FS_MAGIC) && (sblock.fs_magic != FS_MAGIC_LFN)
1023 && (sblock.fs_magic != FD_FSMAGIC)
1024 #if defined(AFS_HPUX101_ENV)
1025 && (sblock.fs_magic != FD_FSMAGIC_2)
1026 #endif
1028 #else
1029 if ((sblock.fs_magic != FS_MAGIC) && (sblock.fs_magic != FS_MAGIC_LFN)) {
1030 #endif
1031 Log("There's something wrong with the superblock for partition %s; bad magic (%d) run vfsck\n", partition, sblock.fs_magic);
1032 goto out;
1034 if (sblock.fs_ncg < 1) {
1035 Log("There's something wrong with the superblock for partition %s; NCG OUT OF RANGE (%d) run vfsck\n", partition, sblock.fs_ncg);
1036 goto out;
1038 if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG) {
1039 Log("There's something wrong with the superblock for partition %s; CPG OUT OF RANGE (%d) run vfsck\n", partition, sblock.fs_cpg);
1040 goto out;
1042 if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl
1043 || (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) {
1044 Log("There's something wrong with the superblock for partition %s; NCYL LESS THAN NCG*CPG run vfsck\n", partition);
1045 goto out;
1047 if (sblock.fs_sbsize > SBSIZE) {
1048 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);
1049 goto out;
1051 #else
1052 if ((super.fs.fs_magic != FS_MAGIC)
1053 || (super.fs.fs_ncg < 1)
1054 #if defined(AFS_SUN_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1055 || (super.fs.fs_cpg < 1)
1056 #else
1057 || (super.fs.fs_cpg < 1 || super.fs.fs_cpg > MAXCPG)
1058 #endif
1059 || (super.fs.fs_ncg * super.fs.fs_cpg < super.fs.fs_ncyl
1060 || (super.fs.fs_ncg - 1) * super.fs.fs_cpg >= super.fs.fs_ncyl)
1061 || (super.fs.fs_sbsize > SBSIZE)) {
1062 Log("There's something wrong with the superblock for partition %s; run vfsck\n", partition);
1063 goto out;
1065 #endif /* AFS_HPUX_ENV */
1067 #ifdef AFS_HPUX_ENV
1068 bufsize = sblock.fs_ipg * sizeof(struct dinode);
1069 #else
1070 bufsize = super.fs.fs_ipg * sizeof(struct dinode);
1071 #endif /* AFS_HPUX_ENV */
1072 inodes = (struct dinode *)malloc(bufsize);
1073 einodes = (struct dinode *)(((char *)inodes) + bufsize);
1074 if (inodes == NULL) {
1075 Log("Unable to allocate enough memory to scan inodes; help!\n");
1076 goto out;
1078 Log("Scanning inodes on device %s...\n", rdev);
1079 #ifdef AFS_HPUX_ENV
1080 for (c = 0; c < sblock.fs_ncg; c++) {
1081 i = c * sblock.fs_ipg;
1082 e = i + sblock.fs_ipg;
1083 #if defined(AFS_HPUX102_ENV)
1084 if (afs_lseek(pfd, dbtoo(fsbtodb(&sblock, itod(&sblock, i))), L_SET) ==
1085 -1) {
1086 #else
1087 if (afs_lseek(pfd, dbtob(fsbtodb(&sblock, itod(&sblock, i))), L_SET) ==
1088 -1) {
1089 #endif
1090 #else
1091 for (c = 0; c < super.fs.fs_ncg; c++) {
1092 daddr_t dblk1;
1093 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
1094 daddr_t f1;
1095 #if defined(AFS_DARWIN_ENV)
1096 #define offset_t off_t
1097 #define llseek lseek
1098 #endif
1099 offset_t off;
1100 #endif /* AFS_SUN5_ENV */
1101 i = c * super.fs.fs_ipg;
1102 e = i + super.fs.fs_ipg;
1103 #ifdef AFS_OSF_ENV
1104 dblk1 = fsbtodb(&super.fs, itod(&super.fs, i));
1105 if (afs_lseek(pfd, (off_t) ((off_t) dblk1 * DEV_BSIZE), L_SET) == -1) {
1106 #else
1107 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
1108 f1 = fsbtodb(&super.fs, itod(&super.fs, i));
1109 off = (offset_t) f1 << DEV_BSHIFT;
1110 if (llseek(pfd, off, L_SET) == -1) {
1111 #else
1112 if (afs_lseek(pfd, dbtob(fsbtodb(&super.fs, itod(&super.fs, i))), L_SET)
1113 == -1) {
1114 #endif /* AFS_SUN5_ENV */
1115 #endif /* AFS_OSF_ENV */
1116 #endif /* AFS_HPUX_ENV */
1117 Log("Error reading inodes for partition %s; run vfsck\n",
1118 partition);
1119 goto out;
1121 while (i < e) {
1122 if (!forceR) {
1123 if (read(pfd, inodes, bufsize) != bufsize) {
1124 Log("Error reading inodes for partition %s; run vfsck\n",
1125 partition);
1126 goto out;
1128 } else {
1129 int bj, bk;
1130 dptr = inodes;
1131 for (bj = bk = 0; bj < bufsize; bj = bj + 512, bk++) {
1132 if ((code = read(pfd, dptr, 512)) != 512) {
1133 Log("Error reading inode %d? for partition %s (errno = %d); run vfsck\n", bk + i, partition, errno);
1134 if (afs_lseek(pfd, 512, L_SET) == -1) {
1135 Log("Lseek failed\n");
1136 goto out;
1138 dptr->di_mode = 0;
1139 dptr++;
1140 dptr->di_mode = 0;
1141 dptr++;
1142 dptr->di_mode = 0;
1143 dptr++;
1144 dptr->di_mode = 0;
1145 dptr++;
1146 } else
1147 dptr += 4;
1150 for (p = inodes; p < einodes && i < e; i++, p++) {
1151 #ifdef notdef
1152 Log("Ino=%d, v1=%x, v2=%x, v3=%x, mode=%x size=%d, lcnt=%d\n",
1153 i, p->di_vicep1, p->di_vicep2, p->di_vicep3, p->di_mode,
1154 p->di_size, p->di_nlink);
1155 printf
1156 ("Ino=%d, v1=%x, v2=%x, v3=%x, mode=%x size=%d, lcnt=%d\n",
1157 i, p->di_vicep1, p->di_vicep2, p->di_vicep3, p->di_mode,
1158 p->di_size, p->di_nlink);
1159 #endif
1160 #ifdef AFS_OSF_ENV
1161 #ifdef AFS_3DISPARES
1162 /* Check to see if this inode is a pre-"OSF1 4.0D" inode */
1163 if ((p->di_uid || p->di_gid)
1164 && !(p->di_flags & (IC_XUID | IC_XGID))) {
1165 Log("Found unconverted inode %d: Use 'fs_conv_dux40D convert' on partition %s\n", i, partition);
1166 goto out;
1168 #else
1169 osi_Panic("Tru64 needs AFS_3DISPARES\n");
1170 #endif
1171 #endif
1172 #if defined(AFS_SUN56_ENV)
1173 /* if this is a pre-sol2.6 unconverted inode, bail out */
1175 afs_uint32 p1, p2, p3, p4;
1176 int p5;
1177 quad *q;
1179 q = (quad *) & (p->di_ic.ic_lsize);
1180 p1 = p->di_gen;
1181 p2 = p->di_ic.ic_flags;
1182 p3 = q->val[0];
1183 p4 = p->di_ic.ic_uid;
1184 p5 = p->di_ic.ic_gid;
1186 if ((p2 || p3) && !p4 && (p5 == -2)) {
1187 Log("Found unconverted inode %d\n", i);
1188 Log("You should run the AFS file conversion utility\n");
1189 goto out;
1192 #endif
1193 if (IS_DVICEMAGIC(p) && (p->di_mode & IFMT) == IFREG) {
1194 afs_uint32 p2 = p->di_vicep2, p3 = DI_VICEP3(p);
1196 info.u.param[0] = p->di_vicep1;
1197 #ifdef AFS_3DISPARES
1198 if (((p2 >> 3) == INODESPECIAL) && (p2 & 0x3)) {
1199 info.u.param[1] = INODESPECIAL;
1200 info.u.param[2] = p3;
1201 info.u.param[3] = p2 & 0x3;
1202 } else {
1203 info.u.param[1] = ((p2 >> 27) << 16) + (p3 & 0xffff);
1204 info.u.param[2] = (p2 & 0x3fffff);
1205 info.u.param[3] =
1206 (((p2 >> 22) & 0x1f) << 16) + (p3 >> 16);
1208 #else
1209 info.u.param[1] = p->di_vicep2;
1210 info.u.param[2] = DI_VICEP3(p);
1211 info.u.param[3] = p->di_vicep4;
1212 #endif
1213 info.inodeNumber = i;
1214 info.byteCount = p->di_size;
1215 info.linkCount = p->di_nlink;
1216 if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
1217 continue;
1218 if (inodeFile) {
1219 if (fwrite(&info, sizeof info, 1, inodeFile) != 1) {
1220 Log("Error writing inode file for partition %s\n",
1221 partition);
1222 goto out;
1225 ninodes++;
1230 if (inodes)
1231 free(inodes);
1232 #endif
1233 if (inodeFile) {
1234 if (fflush(inodeFile) == EOF) {
1235 Log("Unable to successfully flush inode file for %s\n", partition);
1236 err = -2;
1237 goto out1;
1239 if (fsync(fileno(inodeFile)) == -1) {
1240 Log("Unable to successfully fsync inode file for %s\n", partition);
1241 err = -2;
1242 goto out1;
1246 * Paranoia: check that the file is really the right size
1248 if (fstat(fileno(inodeFile), &status) == -1) {
1249 Log("Unable to successfully stat inode file for %s\n", partition);
1250 err = -2;
1251 goto out1;
1253 if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
1254 Log("Wrong size (%d instead of %d) in inode file for %s\n",
1255 status.st_size, ninodes * sizeof(struct ViceInodeInfo),
1256 partition);
1257 err = -2;
1258 goto out1;
1261 close(pfd);
1262 return 0;
1264 out:
1265 err = -1;
1266 out1:
1267 close(pfd);
1268 if (inodes)
1269 free(inodes);
1270 return err;
1272 #endif /* !AFS_SGI_ENV */
1273 #endif /* !AFS_AIX31_ENV */
1275 #ifdef AFS_DARWIN_ENV
1276 #undef dbtob
1277 #define dbtob(db) ((unsigned)(db) << DEV_BSHIFT)
1278 #endif
1281 bread(int fd, char *buf, daddr_t blk, afs_int32 size)
1283 #ifdef AFS_AIX_ENV
1284 #ifdef AFS_AIX41_ENV
1285 offset_t off = (offset_t) blk << FSBSHIFT;
1286 if (llseek(fd, off, 0) < 0) {
1287 Log("Unable to seek to offset %llu for block %u\n", off, blk);
1288 return -1;
1290 #else /* AFS_AIX41_ENV */
1291 if (afs_lseek(fd, blk * Bsize, 0) < 0) {
1292 Log("Unable to seek to offset %u for block %u\n", blk * Bsize, blk);
1294 #endif /* AFS_AIX41_ENV */
1295 #else
1296 if (afs_lseek(fd, (off_t) dbtob(blk), L_SET) < 0) {
1297 Log("Unable to seek to offset %u for block %u\n", dbtob(blk), blk);
1299 #endif
1300 if (read(fd, buf, size) != size) {
1301 Log("Unable to read block %d, partition %s\n", blk, partition);
1302 return -1;
1304 return 0;
1307 #endif /* AFS_LINUX20_ENV */
1308 static afs_int32
1309 convertVolumeInfo(FdHandle_t *fdhr, FdHandle_t *fdhw, afs_uint32 vid)
1311 struct VolumeDiskData vd;
1312 char *p;
1314 if (FDH_PREAD(fdhr, &vd, sizeof(struct VolumeDiskData), 0) !=
1315 sizeof(struct VolumeDiskData)) {
1316 Log("1 convertiVolumeInfo: read failed for %lu with code %d\n", vid,
1317 errno);
1318 return -1;
1320 vd.restoredFromId = vd.id; /* remember the RO volume here */
1321 vd.cloneId = vd.id;
1322 vd.id = vd.parentId;
1323 vd.type = RWVOL;
1324 vd.dontSalvage = 0;
1325 vd.inUse = 0;
1326 vd.uniquifier += 5000; /* just in case there are still file copies
1327 from the old RW volume around */
1329 /* For ROs, the copyDate contains the time that the RO volume was actually
1330 * created, and the creationDate just contains the last time the RO was
1331 * copied from the RW data. So, make the new RW creationDate more accurate
1332 * by setting it to copyDate, if copyDate is older. Since, we know the
1333 * volume is at least as old as copyDate. */
1334 if (vd.copyDate < vd.creationDate) {
1335 vd.creationDate = vd.copyDate;
1336 } else {
1337 /* If copyDate is newer, just make copyDate and creationDate the same,
1338 * for consistency with other RWs */
1339 vd.copyDate = vd.creationDate;
1342 p = strrchr(vd.name, '.');
1343 if (p && !strcmp(p, ".readonly")) {
1344 memset(p, 0, 9);
1347 if (FDH_PWRITE(fdhw, &vd, sizeof(struct VolumeDiskData), 0) !=
1348 sizeof(struct VolumeDiskData)) {
1349 Log("1 convertiVolumeInfo: write failed for %lu with code %d\n", vid,
1350 errno);
1351 return -1;
1353 return 0;
1356 struct specino {
1357 afs_int32 inodeType;
1358 Inode inodeNumber;
1359 Inode ninodeNumber;
1364 UpdateThisVolume(struct ViceInodeInfo *inodeinfo, VolumeId singleVolumeNumber,
1365 struct specino *specinos)
1367 struct dinode *p;
1368 if ((inodeinfo->u.vnode.vnodeNumber == INODESPECIAL) &&
1369 (inodeinfo->u.vnode.volumeId == singleVolumeNumber)) {
1370 specinos[inodeinfo->u.special.type].inodeNumber =
1371 inodeinfo->inodeNumber;
1373 return 0; /* We aren't using a result file, we're caching */
1376 static char *
1377 getDevName(char *pbuffer, char *wpath)
1379 char pbuf[128], *ptr;
1380 strcpy(pbuf, pbuffer);
1381 ptr = (char *)strrchr(pbuf, OS_DIRSEPC);
1382 if (ptr) {
1383 *ptr = '\0';
1384 strcpy(wpath, pbuf);
1385 } else
1386 return NULL;
1387 ptr = (char *)strrchr(pbuffer, OS_DIRSEPC);
1388 if (ptr) {
1389 strcpy(pbuffer, ptr + 1);
1390 return pbuffer;
1391 } else
1392 return NULL;
1395 #ifdef FSSYNC_BUILD_CLIENT
1397 inode_ConvertROtoRWvolume(char *pname, afs_uint32 volumeId)
1399 char dir_name[512], oldpath[512], newpath[512];
1400 char volname[20];
1401 char headername[16];
1402 char *name;
1403 int fd, err, forcep, j;
1404 ssize_t len, nBytes;
1405 struct dirent *dp;
1406 struct DiskPartition64 *partP;
1407 struct ViceInodeInfo info;
1408 struct VolumeDiskHeader h;
1409 IHandle_t *ih, *ih2;
1410 FdHandle_t *fdP, *fdP2;
1411 afs_foff_t offset;
1412 char wpath[100];
1413 char tmpDevName[100];
1414 char buffer[128];
1415 struct specino specinos[VI_LINKTABLE+1];
1416 Inode nearInode = 0;
1417 # ifdef AFS_DEMAND_ATTACH_FS
1418 int locktype = 0;
1419 # endif /* AFS_DEMAND_ATTACH_FS */
1420 int code = 0;
1422 memset(&specinos, 0, sizeof(specinos));
1424 /* now do the work */
1426 for (partP = DiskPartitionList; partP && strcmp(partP->name, pname);
1427 partP = partP->next);
1428 if (!partP) {
1429 Log("1 inode_ConvertROtoRWvolume: Couldn't find DiskPartition for %s\n", pname);
1430 code = EIO;
1431 goto done;
1434 #ifdef AFS_DEMAND_ATTACH_FS
1435 locktype = VVolLockType(V_VOLUPD, 1);
1436 code = VLockVolumeByIdNB(volumeId, partP, locktype);
1437 if (code) {
1438 locktype = 0;
1439 code = EIO;
1440 goto done;
1442 #endif
1444 if (VReadVolumeDiskHeader(volumeId, partP, &h)) {
1445 Log("1 inode_ConvertROtoRWvolume: Couldn't read header for RO-volume %lu.\n",
1446 afs_printable_uint32_lu(volumeId));
1447 return EIO;
1450 FSYNC_VolOp(volumeId, pname, FSYNC_VOL_BREAKCBKS, 0, NULL);
1452 strcpy(tmpDevName, partP->devName);
1453 name = getDevName(tmpDevName, wpath);
1455 if ((err = ListViceInodes(name, VPartitionPath(partP),
1456 NULL, UpdateThisVolume, volumeId,
1457 &forcep, 0, wpath, &specinos)) < 0)
1459 Log("1 inode_ConvertROtoRWvolume: Couldn't get special inodes\n");
1460 code = EIO;
1461 goto done;
1464 #if defined(NEARINODE_HINT)
1465 nearInodeHash(volumeId, nearInode);
1466 nearInode %= partP->f_files;
1467 #endif
1469 for (j = VI_VOLINFO; j < VI_LINKTABLE+1; j++) {
1470 if (specinos[j].inodeNumber > 0) {
1471 specinos[j].ninodeNumber =
1472 IH_CREATE(NULL, partP->device, VPartitionPath(partP),
1473 nearInode, h.parent, INODESPECIAL, j, h.parent);
1474 IH_INIT(ih, partP->device, volumeId,
1475 specinos[j].inodeNumber);
1476 fdP = IH_OPEN(ih);
1477 if (!fdP) {
1478 Log("1 inode_ConvertROtoRWvolume: Couldn't find special inode %d for %d\n", j, volumeId);
1479 code = -1;
1480 goto done;
1483 IH_INIT(ih2, partP->device, h.parent, specinos[j].ninodeNumber);
1484 fdP2 = IH_OPEN(ih2);
1485 if (!fdP2) {
1486 Log("1 inode_ConvertROtoRWvolume: Couldn't find special inode %d for %d\n", j, h.parent);
1487 code = -1;
1488 goto done;
1491 if (j == VI_VOLINFO)
1492 convertVolumeInfo(fdP, fdP2, ih2->ih_vid);
1493 else {
1494 offset = 0;
1495 while (1) {
1496 len = FDH_PREAD(fdP, buffer, sizeof(buffer), offset);
1497 if (len < 0)
1498 return errno;
1499 if (len == 0)
1500 break;
1501 nBytes = FDH_PWRITE(fdP2, buffer, len, offset);
1502 if (nBytes != len) {
1503 code = -1;
1504 goto done;
1506 offset += len;
1510 FDH_CLOSE(fdP);
1511 FDH_CLOSE(fdP2);
1513 /* Unlink the old special inode; otherwise we will get duplicate
1514 * special inodes if we recreate the RO again */
1515 if (IH_DEC(ih, specinos[j].inodeNumber, volumeId) == -1) {
1516 afs_ino_str_t stmp;
1517 Log("IH_DEC failed: %x, %s, %u errno %d\n", ih,
1518 PrintInode(stmp, specinos[j].inodeNumber), volumeId, errno);
1521 IH_RELEASE(ih);
1522 IH_RELEASE(ih2);
1526 h.id = h.parent;
1527 #ifdef AFS_64BIT_IOPS_ENV
1528 h.volumeInfo_lo = (afs_int32)specinos[VI_VOLINFO].ninodeNumber & 0xffffffff;
1529 h.volumeInfo_hi = (afs_int32)(specinos[VI_VOLINFO].ninodeNumber >> 32) && 0xffffffff;
1530 h.smallVnodeIndex_lo = (afs_int32)specinos[VI_SMALLINDEX].ninodeNumber & 0xffffffff;
1531 h.smallVnodeIndex_hi = (afs_int32)(specinos[VI_SMALLINDEX].ninodeNumber >> 32) & 0xffffffff;
1532 h.largeVnodeIndex_lo = (afs_int32)specinos[VI_LARGEINDEX].ninodeNumber & 0xffffffff;
1533 h.largeVnodeIndex_hi = (afs_int32)(specinos[VI_LARGEINDEX].ninodeNumber >> 32) & 0xffffffff;
1534 if (specinos[VI_LINKTABLE].ninodeNumber) {
1535 h.linkTable_lo = (afs_int32)specinos[VI_LINKTABLE].ninodeNumber & 0xffffffff;
1536 h.linkTable_hi = (afs_int32)specinos[VI_LINKTABLE].ninodeNumber & 0xffffffff;
1538 #else
1539 h.volumeInfo_lo = specinos[VI_VOLINFO].ninodeNumber;
1540 h.smallVnodeIndex_lo = specinos[VI_SMALLINDEX].ninodeNumber;
1541 h.largeVnodeIndex_lo = specinos[VI_LARGEINDEX].ninodeNumber;
1542 if (specinos[VI_LINKTABLE].ninodeNumber) {
1543 h.linkTable_lo = specinos[VI_LINKTABLE].ninodeNumber;
1545 #endif
1547 if (VCreateVolumeDiskHeader(&h, partP)) {
1548 Log("1 inode_ConvertROtoRWvolume: Couldn't write header for RW-volume %lu\n",
1549 afs_printable_uint32_lu(h.id));
1550 code = EIO;
1551 goto done;
1554 if (VDestroyVolumeDiskHeader(partP, volumeId, h.parent)) {
1555 Log("1 inode_ConvertROtoRWvolume: Couldn't unlink header for RO-volume %lu\n",
1556 afs_printable_uint32_lu(volumeId));
1559 FSYNC_VolOp(volumeId, pname, FSYNC_VOL_DONE, 0, NULL);
1560 FSYNC_VolOp(h.id, pname, FSYNC_VOL_ON, 0, NULL);
1562 done:
1563 # ifdef AFS_DEMAND_ATTACH_FS
1564 if (locktype) {
1565 VUnlockVolumeById(volumeId, partP);
1567 # endif /* AFS_DEMAND_ATTACH_FS */
1568 return code;
1570 #endif /* FSSYNC_BUILD_CLIENT */
1571 #endif /* AFS_NAMEI_ENV */