pci: don't do sanity check for missing pci bus, the check can misfire.
[minix.git] / commands / simple / swapfs.c
blob10bd86c23bb32643a9cf7da0417495ef3a3fd2f9
1 /* swapfs - swap a Minix file system Author: Niels C. Willems */
4 /* $Id$ */
6 /* Swapfs, a program to convert V1 or V2 Minix file systems from big endian
7 byte order to little endian and vv.
9 Some examples:
10 swapfs -v disk.01 ! only show verbose information.
11 swapfs /dev/fd0 | compress > fd0r.Z ! convert and compress filesystem.
12 swapfs -v fileA fileA ! read, convert and write the same filesystem.
14 This program uses one byte of heap memory for each data block (1Kbytes)
15 in the file system, so with Minix-PC 16-bit you can't swap file systems
16 bigger than about 32 Mbytes
18 Be careful with 'swapfs fileA fileA'. If the program aborts e.g. by
19 user interrupt, power failure or an inconsistent file system, you
20 better have a backup of fileA
22 This program only converts directories and indirect blocks of files
23 that are in use. Converting indirect blocks or directories of deleted
24 files is hard and not yet done.
26 If you have a (1.6.xx, xx < 18) version of Minix that supports the
27 mounting of reversed file systems always mount them read-only and
28 avoid any attemp to modify them (mkdir, open, creat) too!
29 These problems have been fixed in Minix 1.6.18.
31 In this version you can get some more information about the
32 file system with the -d (debug) flag.
34 Please send your bug reports or ideas to ncwille@cs.vu.nl
38 #define _POSIX_SOURCE 1
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <stdlib.h>
43 #include <fcntl.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <stdio.h>
48 #include <assert.h>
50 #if __STDC__ == 1
51 #define _PROTOTYPE(function, params) function params
52 #else
53 #define _PROTOTYPE(function, params) function()
54 #endif
56 #define BLOCK_SIZE 1024
58 #define BOOT_BLOCK_OFF (blockn_t) 0
59 #define SUPER_BLOCK_OFF (blockn_t) 1
61 #define V1_MAGIC 0x137F
62 #define V2_MAGIC 0x2468
63 #define NINODES_OFFSET 0
64 #define V1_ZONES_OFFSET 2
65 #define IMAP_BLOCKS_OFFSET 4
66 #define ZMAP_BLOCKS_OFFSET 6
67 #define FIRSTDATAZONE_OFFSET 8
68 #define LOG_ZONE_SIZE_OFFSET 10
69 #define MAGIC_OFFSET 16
70 #define V2_ZONES_OFFSET 20
73 #define NR_DIRECT_ZONES 7
74 #define V1_NR_TZONES 9
75 #define V2_NR_TZONES 10
76 #define V1_INODE_SIZE 32
77 #define V2_INODE_SIZE 64
79 #define INODE1_MODE_OFF 0
80 #define INODE1_SIZE_OFF 4
81 #define INODE1_DIRECT_OFF 14
82 #define INODE1_IND1_OFF 28
83 #define INODE1_IND2_OFF 30
85 #define INODE2_MODE_OFF 0
86 #define INODE2_SIZE_OFF 8
87 #define INODE2_DIRECT_OFF 24
88 #define INODE2_IND1_OFF 52
89 #define INODE2_IND2_OFF 56
90 #define INODE2_IND3_OFF 60
92 #define INODE_MODE_MASK 0xf000 /* file type mask */
93 #define INODE_DIR_MODE 0x4000 /* directory */
94 #define INODE_BLK_SPECIAL_MODE 0x6000 /* block special */
95 #define INODE_CHR_SPECIAL_MODE 0x2000 /* character special */
97 #define T_MASK 0x1c
98 #define T_UNKNOWN 0x00
99 #define T_MAYBE_OLD_DIR 0x04
100 #define T_OLD_NON_DIR 0x08
101 #define T_DIR 0x0c
102 #define T_NON_DIR 0x10
104 #define INDIRECT_MASK 0x03
106 #define IND_PROCESSED_BIT 0x20 /* set when all blocks in ind block are
107 * marked */
108 #define IND_CONFLICT_BIT 0x40
109 #define TYPE_CONFLICT_BIT 0x80
111 #define DIR_ENTRY_SIZE 16
113 typedef enum {
114 Unused_zone, Old_zone, In_use_zone
115 } class_t;
117 typedef unsigned long blockn_t;
118 typedef unsigned int inodesn_t;
120 typedef struct {
121 inodesn_t ninodes; /* # usable inodes on the minor device */
122 blockn_t imap_blocks; /* # of blocks used by inode bit map */
123 blockn_t zmap_blocks; /* # of blocks used by zone bit map */
124 blockn_t firstdatazone; /* number of first data zone */
125 int log_zone_size; /* log2 of blocks/zone */
126 blockn_t zones; /* number of zones */
128 int version; /* file system version */
129 inodesn_t inodes_per_block;
130 blockn_t first_imap_block;
131 blockn_t first_zmap_block;
132 blockn_t first_inode_block; /* number of first block with inodes */
133 size_t dzmap_size; /* # of data zone blocks */
134 } super_t;
137 typedef struct { /* summary of inode */
138 long size; /* current file size in bytes */
139 blockn_t direct[NR_DIRECT_ZONES]; /* block numbers for direct,
140 * ind, ... */
141 blockn_t ind1; /* single indirect block number */
142 blockn_t ind2; /* double indirect block number */
143 blockn_t ind3; /* triple indirect block number */
144 int ztype; /* type of zones that belong to this inode */
145 } inode_t;
147 static char rcsid[] = "$Id$";
149 static int super_format[] = {2, 2, 2, 2, 2, 2, 4, 2, 2, 4, 0};
150 static int inode1_format[] = {2, 2, 4, 4, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0};
151 static int inode2_format[] = {2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
152 4, 4, 0};
154 static char *ind_str[4] = {"direct", "single indirect",
155 "double indirect", "triple indirect"};
157 static int big_endian_fs; /* set in init_super(), 1 iff file system has
158 * big endian byte order */
159 static int verbose_flag;
160 static int debug_flag;
161 static int test_flag;
163 typedef unsigned char *dzmap_t;
166 int _PROTOTYPE(main, (int argc, char *argv[]));
167 static void _PROTOTYPE(parse_args_init_io, (int argc, char *argv[]));
168 static void _PROTOTYPE(rw_boot, (void));
169 static void _PROTOTYPE(rw_init_super, (super_t * sp));
170 static void _PROTOTYPE(init_dzmap, (dzmap_t * dzmap_ptr, size_t dzmap_size));
171 static void _PROTOTYPE(rw_ibmap, (super_t super));
172 static void _PROTOTYPE(rw_zbmap, (super_t super));
173 static void _PROTOTYPE(print_stat, (dzmap_t dzmap, super_t super));
174 static void _PROTOTYPE(p1_rw_inodes, (dzmap_t dzmap, super_t super));
175 static void _PROTOTYPE(rd_indirects, (dzmap_t dzmap, super_t super, int ind,
176 class_t required_class));
177 static void _PROTOTYPE(rw_data_zones, (dzmap_t dzmap, super_t super));
179 static int _PROTOTYPE(read_block, (char *buf, blockn_t offset));
180 static void _PROTOTYPE(write_block, (char *buf));
181 static int _PROTOTYPE(convcpy, (char *dst, char *src, int *format));
182 static void _PROTOTYPE(conv2_blkcpy, (char *dst, char *src));
183 static void _PROTOTYPE(conv4_blkcpy, (char *dst, char *src));
184 static void _PROTOTYPE(conv2cpy, (char *dst, char *src));
185 static int _PROTOTYPE(inode_size, (int version));
187 static void _PROTOTYPE(init_super, (super_t * sp, char *buf));
188 static void _PROTOTYPE(get_inode, (inode_t * ip, char *buf, int version));
189 static int _PROTOTYPE(check_inode, (inode_t inode, super_t super));
190 static int _PROTOTYPE(was_blk_special, (inode_t inode));
191 static int _PROTOTYPE(check_blk_number, (blockn_t num, super_t super));
192 static void _PROTOTYPE(cw_inode_block, (char *buf, inodesn_t ninodes,
193 int version));
194 static void _PROTOTYPE(proc_ind, (dzmap_t dzmap, size_t curr_ind,
195 char *buf, super_t super));
196 static void _PROTOTYPE(cw_dir_block, (char *buf));
197 static void _PROTOTYPE(dzmap_add_inode, (dzmap_t dzmap, inode_t inode,
198 super_t super));
199 static void _PROTOTYPE(dz_update, (dzmap_t dzmap, blockn_t blknum,
200 int new_indnum, int new_ztype, super_t super));
201 static class_t _PROTOTYPE(ztype_class, (int ztype));
203 static unsigned int _PROTOTYPE(two_bytes, (char buf[2]));
204 static long _PROTOTYPE(four_bytes, (char buf[4]));
206 static void _PROTOTYPE(fail, (char *string));
207 static void _PROTOTYPE(usage, (char *arg0));
210 int main(argc, argv)
211 int argc;
212 char *argv[];
214 super_t super;
215 dzmap_t dzmap;
217 parse_args_init_io(argc, argv);
218 rw_boot();
219 rw_init_super(&super);
220 init_dzmap(&dzmap, super.dzmap_size);
221 rw_ibmap(super);
222 rw_zbmap(super);
223 p1_rw_inodes(dzmap, super);
225 rd_indirects(dzmap, super, 3, In_use_zone);
226 rd_indirects(dzmap, super, 2, In_use_zone);
227 rd_indirects(dzmap, super, 1, In_use_zone);
228 if (verbose_flag) putc('\n', stderr);
230 print_stat(dzmap, super);
231 rw_data_zones(dzmap, super);
232 return 0;
236 static void parse_args_init_io(argc, argv)
237 int argc;
238 char *argv[];
240 char *str;
241 struct stat buf;
242 ino_t src_ino;
243 int i;
245 debug_flag = 0;
246 verbose_flag = 0;
247 test_flag = 0;
249 for (i = 1; i < argc; i++) {
250 str = argv[i];
251 if (*str != '-') break;
252 switch (*++str) {
253 case 'v': verbose_flag = 1; break;
254 case 'd':
255 debug_flag = 1;
256 verbose_flag = 1;
257 break;
258 case 't': test_flag = 1; break;
259 default: usage(argv[0]);
262 if ((argc - i == 0 && isatty(0)) || (argc - i) > 2) usage(argv[0]);
264 if (argc - i > 0) {
265 (void) close(0);
266 if (open(argv[i], O_RDONLY) != 0) {
267 fprintf(stderr, "Can't open input file %s", argv[i]);
268 fail("");
271 if (isatty(1) || argc - i == 2) {
272 if (argc - i < 2)
273 test_flag = 1;
274 else {
275 i++;
276 (void) close(1);
277 (void) fstat(0, &buf);
278 src_ino = buf.st_ino;
279 if (stat(argv[i], &buf) == 0 && src_ino == buf.st_ino) {
280 /* Src and dest are the same */
281 if (open(argv[i], O_WRONLY) != 1) {
282 fprintf(stderr, "Can't open output file %s", argv[i]);
283 fail("");
285 } else if (creat(argv[i], 0644) != 1) {
286 fprintf(stderr, "Can't creat output file %s", argv[i]);
287 fail("");
294 static void rw_boot()
296 char buf[BLOCK_SIZE];
298 if (read_block(buf, BOOT_BLOCK_OFF) != BLOCK_SIZE)
299 fail("Can't read bootblock");
300 write_block(buf);
304 static void rw_init_super(sp)
305 super_t *sp;
307 char ibuf[BLOCK_SIZE], obuf[BLOCK_SIZE];
309 if (read_block(ibuf, SUPER_BLOCK_OFF) != BLOCK_SIZE)
310 fail("Can't read superblock");
312 init_super(sp, ibuf);
314 memcpy(obuf, ibuf, (size_t) BLOCK_SIZE); /* preserve 'unused' data */
315 (void) convcpy(obuf, ibuf, super_format);
317 write_block(obuf);
321 static void init_dzmap(dzmap_ptr, dzmap_size)
322 dzmap_t *dzmap_ptr;
323 size_t dzmap_size;
325 if ((*dzmap_ptr = (dzmap_t) malloc(dzmap_size)) == (dzmap_t) NULL)
326 fail("Not enough space for data zone map");
327 memset(*dzmap_ptr, '\0', (size_t) dzmap_size);
331 static void rw_ibmap(super)
332 super_t super;
334 char ibuf[BLOCK_SIZE], obuf[BLOCK_SIZE];
335 blockn_t i;
337 for (i = 0; i < super.imap_blocks; i++) {
338 if (read_block(ibuf, super.first_imap_block + i) != BLOCK_SIZE)
339 fail("Can't read inode bit map");
340 conv2_blkcpy(obuf, ibuf);
341 write_block(obuf);
346 static void rw_zbmap(super)
347 super_t super;
349 char ibuf[BLOCK_SIZE], obuf[BLOCK_SIZE];
350 blockn_t i;
352 for (i = 0; i < super.zmap_blocks; i++) {
353 if (read_block(ibuf, super.first_zmap_block + i) != BLOCK_SIZE)
354 fail("Can't read zone bit map");
355 conv2_blkcpy(obuf, ibuf);
356 write_block(obuf);
361 static void p1_rw_inodes(dzmap, super)
362 dzmap_t dzmap;
363 super_t super;
365 char buf[BLOCK_SIZE], *buf_ptr;
366 inodesn_t i, num_inodes;
367 blockn_t next_block;
368 inode_t inode;
371 next_block = super.first_inode_block;
373 for (i = 1; i <= super.ninodes; i++) {
374 if ((i - 1) % super.inodes_per_block == 0) {
375 if (read_block(buf, next_block) != BLOCK_SIZE)
376 fail("read failed in inode block");
377 buf_ptr = buf;
378 next_block++;
379 num_inodes = super.ninodes + 1 - i;
380 if (num_inodes > super.inodes_per_block)
381 num_inodes = super.inodes_per_block;
382 cw_inode_block(buf, num_inodes, super.version);
384 get_inode(&inode, buf_ptr, super.version);
385 dzmap_add_inode(dzmap, inode, super);
386 buf_ptr += inode_size(super.version);
391 static void print_stat(dzmap, super)
392 dzmap_t dzmap;
393 super_t super;
395 size_t i;
396 register unsigned char dz;
397 int both_conflict = 0, ind_conflict = 0, type_conflict = 0, unreferenced = 0;
398 int not_in_use = 0;
400 if (!verbose_flag) return;
402 for (i = 0; i < super.dzmap_size; i++) {
403 dz = dzmap[i];
404 if (dz & IND_CONFLICT_BIT && dz & TYPE_CONFLICT_BIT)
405 both_conflict++;
406 else if (dz & IND_CONFLICT_BIT)
407 ind_conflict++;
408 else if (dz & TYPE_CONFLICT_BIT)
409 type_conflict++;
411 if (dz == 0) unreferenced++;
412 if (ztype_class(dz & T_MASK) < In_use_zone) not_in_use++;
415 if (debug_flag) {
416 fprintf(stderr, "%5d zone blocks with conflicting indir.\n",
417 ind_conflict);
418 fprintf(stderr, "%5d zone blocks with conflicting types.\n",
419 type_conflict);
420 fprintf(stderr, "%5d zone blocks with conflicting types and indir.\n",
421 both_conflict);
422 fprintf(stderr, "%5d zone blocks never referenced.\n", unreferenced);
424 fprintf(stderr, "%5d zone blocks not in use.\n", not_in_use);
425 putc('\n', stderr);
429 static void rd_indirects(dzmap, super, ind, required_class)
430 dzmap_t dzmap;
431 super_t super;
432 int ind;
433 class_t required_class;
435 size_t i;
436 int ind_cnt;
437 off_t dz_offset;
438 char buf[BLOCK_SIZE];
440 dz_offset = super.firstdatazone;
441 ind_cnt = 0;
442 for (i = 0; i < super.dzmap_size; i++) {
443 if (ztype_class(dzmap[i] & T_MASK) != required_class ||
444 (dzmap[i] & INDIRECT_MASK) != ind ||
445 (dzmap[i] & IND_PROCESSED_BIT))
446 continue;
448 ind_cnt++;
449 if (read_block(buf, dz_offset + i) != BLOCK_SIZE) {
450 fprintf(stderr, "Can't read %s block", ind_str[ind]);
451 fail("");
453 proc_ind(dzmap, i, buf, super);
455 if ((verbose_flag && ind_cnt > 0) || debug_flag)
456 fprintf(stderr, "%5d %s zone blocks.\n", ind_cnt, ind_str[ind]);
460 static void rw_data_zones(dzmap, super)
461 dzmap_t dzmap;
462 super_t super;
464 char ibuf[BLOCK_SIZE], obuf[BLOCK_SIZE];
465 size_t i;
466 int ztype, ind, last_read;
467 off_t dz_offset;
469 dz_offset = super.firstdatazone;
470 for (i = 0; i < super.dzmap_size; i++) {
471 last_read = read_block(ibuf, dz_offset + i);
472 if (last_read != BLOCK_SIZE) break;
474 ind = dzmap[i] & INDIRECT_MASK;
475 if (ind == 0) {
476 ztype = dzmap[i] & T_MASK;
477 if (ztype == T_DIR)
478 cw_dir_block(ibuf);
479 else
480 write_block(ibuf);
481 } else {
482 if (super.version == 1)
483 conv2_blkcpy(obuf, ibuf);
484 else
485 conv4_blkcpy(obuf, ibuf);
486 write_block(obuf);
488 if (verbose_flag && i && i % 1024 == 0) {
489 fprintf(stderr, ".");
490 fflush(stderr);
493 if (verbose_flag && i > 1024) putc('\n', stderr);
495 if (last_read != BLOCK_SIZE) for (; i < super.dzmap_size; i++)
496 if (ztype_class(dzmap[i] & T_MASK) == In_use_zone)
497 fail("Can't read data zone");
501 static int read_block(buf, offset)
502 char *buf;
503 blockn_t offset;
505 static blockn_t curr_offset = 0;
506 int bytes;
508 if (offset != curr_offset) {
509 if (lseek(0, (off_t) offset * BLOCK_SIZE, 0) == -1)
510 fail("lseek failed on input file");
511 curr_offset = offset;
513 bytes = read(0, buf, BLOCK_SIZE);
514 if (bytes < 0) fail("read failed on input file");
516 curr_offset += bytes;
518 return bytes;
522 static void write_block(buf)
523 char *buf;
525 if (test_flag) return;
527 if (write(1, buf, BLOCK_SIZE) != BLOCK_SIZE)
528 fail("write failed on output file");
532 static int convcpy(dst, src, format)
533 char *dst;
534 char *src;
535 int *format;
537 char *old_src = src;
538 register char tmp;
539 int i;
541 for (i = 0; format[i] > 0; i++) {
542 switch (format[i]) {
543 case 1: *dst++ = *src++; break;
544 case 2:
545 tmp = *src++;
546 *dst++ = *src++;
547 *dst++ = tmp;
548 break;
549 case 4:
550 tmp = src[0];
551 dst[0] = src[3];
552 dst[3] = tmp;
553 tmp = src[1];
554 dst[1] = src[2];
555 dst[2] = tmp;
556 src += 4;
557 dst += 4;
558 break;
559 default:
560 fail("wrong format array for convcpy");
563 return(src - old_src);
567 static void conv2_blkcpy(dst, src)
568 char *dst;
569 char *src;
571 int i;
572 register char tmp;
574 for (i = 0; i < BLOCK_SIZE; i += 2) {
575 tmp = *src++;
576 *dst++ = *src++;
577 *dst++ = tmp;
582 static void conv4_blkcpy(dst, src)
583 char *dst;
584 char *src;
586 int i;
587 register char tmp;
589 for (i = 0; i < BLOCK_SIZE; i += 4) {
590 tmp = src[0];
591 dst[0] = src[3];
592 dst[3] = tmp;
594 tmp = src[1];
595 dst[1] = src[2];
596 dst[2] = tmp;
598 src += 4;
599 dst += 4;
604 static void conv2cpy(dst, src)
605 char *dst;
606 char *src;
608 register char tmp;
609 tmp = *src++;
610 *dst++ = *src++;
611 *dst++ = tmp;
615 static int inode_size(version)
616 int version;
618 return(version == 1) ? V1_INODE_SIZE : V2_INODE_SIZE;
622 static void init_super(sp, buf)
623 super_t *sp;
624 char *buf;
626 int magic;
627 long imapblks, zmapblks;
629 big_endian_fs = 0; /* guess the file system is little endian */
630 magic = two_bytes(buf + MAGIC_OFFSET);
632 if (magic != V1_MAGIC && magic != V2_MAGIC) {
633 big_endian_fs = 1;
634 magic = two_bytes(buf + MAGIC_OFFSET);
636 switch (magic) {
637 case V1_MAGIC: sp->version = 1; break;
638 case V2_MAGIC: sp->version = 2; break;
639 default: fail("Not a Minix file system");
642 if (verbose_flag) fprintf(stderr, "\nVersion = V%d, %s endian.\n",
643 sp->version, big_endian_fs ? "big" : "little");
645 sp->ninodes = two_bytes(buf + NINODES_OFFSET);
646 imapblks = two_bytes(buf + IMAP_BLOCKS_OFFSET);
647 sp->imap_blocks = imapblks;
648 zmapblks = two_bytes(buf + ZMAP_BLOCKS_OFFSET);
649 sp->zmap_blocks = zmapblks;
650 sp->firstdatazone = two_bytes(buf + FIRSTDATAZONE_OFFSET);
651 sp->log_zone_size = two_bytes(buf + LOG_ZONE_SIZE_OFFSET);
653 if (sp->version == 1)
654 sp->zones = two_bytes(buf + V1_ZONES_OFFSET);
655 else
656 sp->zones = four_bytes(buf + V2_ZONES_OFFSET);
658 sp->inodes_per_block = BLOCK_SIZE / inode_size(sp->version);
660 if (imapblks < 0 || zmapblks < 0 || sp->ninodes < 1 || sp->zones < 1)
661 fail("Bad superblock");
664 if (sp->log_zone_size != 0)
665 fail("Can't swap file systems with different zone and block sizes");
667 sp->first_imap_block = SUPER_BLOCK_OFF + 1;
668 sp->first_zmap_block = sp->first_imap_block + sp->imap_blocks;
669 sp->first_inode_block = sp->first_zmap_block + sp->zmap_blocks;
671 sp->dzmap_size = sp->zones - sp->firstdatazone;
672 if (verbose_flag) {
673 fprintf(stderr, "nzones = %ld, ", sp->zones);
674 fprintf(stderr, "ninodes = %u, ", sp->ninodes);
675 fprintf(stderr, "first data zone = %ld.\n\n", sp->firstdatazone);
680 static void get_inode(ip, buf, version)
681 inode_t *ip;
682 char *buf;
683 int version;
685 int i;
686 int mode;
688 if (version == 1) {
689 mode = two_bytes(buf + INODE1_MODE_OFF);
690 ip->size = four_bytes(buf + INODE1_SIZE_OFF);
691 ip->ind1 = two_bytes(buf + INODE1_IND1_OFF);
692 ip->ind2 = two_bytes(buf + INODE1_IND2_OFF);
693 ip->ind3 = 0;
694 for (i = 0; i < NR_DIRECT_ZONES; i++)
695 ip->direct[i] = two_bytes(buf + INODE1_DIRECT_OFF + 2 * i);
696 } else {
697 mode = two_bytes(buf + INODE2_MODE_OFF);
698 ip->size = four_bytes(buf + INODE2_SIZE_OFF);
699 ip->ind1 = four_bytes(buf + INODE2_IND1_OFF);
700 ip->ind2 = four_bytes(buf + INODE2_IND2_OFF);
701 ip->ind3 = four_bytes(buf + INODE2_IND3_OFF);
702 for (i = 0; i < NR_DIRECT_ZONES; i++)
703 ip->direct[i] = four_bytes(buf + INODE2_DIRECT_OFF + 4 * i);
706 if (mode == 0) {
707 if (ip->size % DIR_ENTRY_SIZE == 0)
708 ip->ztype = T_MAYBE_OLD_DIR;
709 else
710 ip->ztype = T_OLD_NON_DIR;
711 if (was_blk_special(*ip)) ip->size = 0;
712 } else {
713 mode = mode & INODE_MODE_MASK;
714 if (mode == INODE_BLK_SPECIAL_MODE || mode == INODE_CHR_SPECIAL_MODE)
715 ip->size = 0; /* prevent the use of the block numbers. */
716 ip->ztype = (mode == INODE_DIR_MODE) ? T_DIR : T_NON_DIR;
721 static int check_inode(inode, super)
722 inode_t inode;
723 super_t super;
725 int i;
727 for (i = 0; i < NR_DIRECT_ZONES; i++)
728 if (!check_blk_number(inode.direct[i], super)) return 0;
730 return(check_blk_number(inode.ind1, super) &&
731 check_blk_number(inode.ind2, super) &&
732 check_blk_number(inode.ind3, super));
736 static int check_blk_number(num, super)
737 blockn_t num;
738 super_t super;
740 if (num == 0 || (num >= super.firstdatazone && num < super.zones))
741 return 1;
743 fprintf(stderr, "warning bad block number %ld in inode.\n", num);
744 return 0;
748 static int was_blk_special(inode)
749 inode_t inode;
751 int i, result;
752 blockn_t block_size;
754 if (inode.size % BLOCK_SIZE || inode.ind1) return 0;
755 block_size = inode.size / BLOCK_SIZE;
757 for (i = NR_DIRECT_ZONES - 1; i >= 0; i--)
758 if (inode.direct[i] != 0) break;
760 result = (i < 1 && block_size > i + 1);
762 if (debug_flag && result) {
763 fprintf(stderr, "old block special file detected (slot = %d).\n", i);
765 return result;
769 static void cw_inode_block(buf, ninodes, version)
770 char *buf;
771 inodesn_t ninodes;
772 int version;
774 char output_buf[BLOCK_SIZE];
775 char *src, *dst;
776 inodesn_t i;
777 int cnt, free_bytes;
778 int *format;
780 src = buf;
781 dst = output_buf;
783 format = (version == 1) ? inode1_format : inode2_format;
784 for (i = 0; i < ninodes; i++) {
785 cnt = convcpy(dst, src, format);
786 src += cnt;
787 dst += cnt;
790 assert(cnt == inode_size(version));
792 free_bytes = BLOCK_SIZE - (src - buf);
793 assert(free_bytes >= 0);
794 if (verbose_flag && free_bytes > 0) {
795 /* There is a small change that the last free inode has no
796 * matching bit in the last inode bit map block: e.g. if
797 * sp->ninodes == 8191. */
798 fprintf(stderr, "%5d bytes (%d inodes) free in last inode block.\n",
799 free_bytes, free_bytes / inode_size(version));
800 memcpy(dst, src, (size_t) free_bytes);
802 write_block(output_buf);
806 static void proc_ind(dzmap, curr_ind, buf, super)
807 dzmap_t dzmap;
808 size_t curr_ind;
809 char *buf;
810 super_t super;
812 int indnum, i, ztype;
813 int word_size; /* size of zone block number in ind. block in
814 * bytes */
815 unsigned char dz, tmp_dz;
816 blockn_t blk, ind_blk;
817 int bad_range = 0, hidden_zero = 0, zero_flag = 0, expired = 0;
818 size_t blk_index;
820 dz = dzmap[curr_ind];
821 indnum = dz & INDIRECT_MASK;
822 ztype = dz & T_MASK;
823 ind_blk = curr_ind + super.firstdatazone;
825 word_size = (super.version == 1) ? 2 : 4;
826 assert(indnum > 0);
828 for (i = 0; i < BLOCK_SIZE; i += word_size) {
829 if (word_size == 2)
830 blk = two_bytes(buf + i);
831 else
832 blk = four_bytes(buf + i);
834 if (blk == 0)
835 zero_flag = 1;
836 else if (blk < super.firstdatazone || blk >= super.zones)
837 bad_range = 1;
838 else {
839 if (zero_flag) hidden_zero = 1;
840 blk_index = blk - super.firstdatazone;
841 tmp_dz = dzmap[blk_index];
842 if (ztype_class(tmp_dz & T_MASK) == In_use_zone) expired = 1;
847 if (ztype_class(ztype) == In_use_zone) {
848 if (bad_range) {
849 fprintf(stderr, "%s zone block contains ", ind_str[indnum]);
850 fail("illegal value");
852 if ((ztype == T_DIR || indnum > 1) && hidden_zero) {
853 fprintf(stderr, "WARNING: %s zone block %ld contains ",
854 ind_str[indnum], ind_blk);
855 fprintf(stderr, "unexpected zero block numbers\n");
857 } else {
858 if (expired) {
859 dzmap[curr_ind] &= ~(INDIRECT_MASK & IND_CONFLICT_BIT);
860 return;
863 /* Not yet implemented. :-( if (bad_range || (indnum > 1 &&
864 * hidden_zero) || equal_values(buf, super.version ) { } */
867 for (i = 0; i < BLOCK_SIZE; i += word_size) {
868 if (word_size == 2)
869 blk = two_bytes(buf + i);
870 else
871 blk = four_bytes(buf + i);
873 if (blk == 0) continue;
874 blk_index = blk - super.firstdatazone;
875 tmp_dz = dzmap[blk_index];
876 if (ztype_class(tmp_dz & T_MASK) == In_use_zone) { /* trouble */
877 if ((tmp_dz & INDIRECT_MASK) == indnum - 1 &&
878 (tmp_dz & T_MASK) == ztype)
879 fprintf(stderr, "WARNING: %s zone block %ld used more \
880 than once\n", ind_str[indnum - 1], blk);
881 else {
882 fprintf(stderr, "Block %ld used more than ", blk);
883 fail("once with different types");
886 dzmap[blk_index] = (dz & ~INDIRECT_MASK) | (indnum - 1);
888 dzmap[curr_ind] |= IND_PROCESSED_BIT;
892 static void cw_dir_block(buf)
893 char *buf;
895 char output_buf[BLOCK_SIZE];
896 int ino, i, old_ino_offset;
898 memcpy(output_buf, buf, BLOCK_SIZE);
900 for (i = 0; i < BLOCK_SIZE; i += DIR_ENTRY_SIZE) {
901 ino = two_bytes(buf + i);
902 if (ino == 0) {
903 old_ino_offset = i + DIR_ENTRY_SIZE - 2;
904 conv2cpy(output_buf + old_ino_offset, buf + old_ino_offset);
905 } else
906 conv2cpy(output_buf + i, buf + i);
908 write_block(output_buf);
912 static void dzmap_add_inode(dzmap, inode, super)
913 dzmap_t dzmap;
914 inode_t inode;
915 super_t super;
917 int i;
919 if (inode.size == 0 || !check_inode(inode, super)) return;
921 for (i = 0; i < NR_DIRECT_ZONES; i++)
922 dz_update(dzmap, inode.direct[i], 0, inode.ztype, super);
924 dz_update(dzmap, inode.ind1, 1, inode.ztype, super);
925 dz_update(dzmap, inode.ind2, 2, inode.ztype, super);
926 dz_update(dzmap, inode.ind3, 3, inode.ztype, super);
930 static void dz_update(dzmap, blknum, new_indnum, new_ztype, super)
931 dzmap_t dzmap;
932 blockn_t blknum;
933 int new_indnum;
934 int new_ztype;
935 super_t super;
937 size_t dznum;
938 int old_indnum;
939 int old_ztype;
940 unsigned char *dz;
941 char new_dz;
944 if (blknum == 0) return;
946 dznum = (size_t) (blknum - super.firstdatazone);
948 dz = &dzmap[dznum];
949 old_indnum = *dz & INDIRECT_MASK;
950 old_ztype = *dz & T_MASK;
952 new_dz = new_ztype | new_indnum;
954 if (ztype_class(new_ztype) > ztype_class(old_ztype)) {
955 *dz = new_dz;
956 return;
957 } else if (ztype_class(new_ztype) < ztype_class(old_ztype))
958 return;
960 /* Collision: old and new have the same class */
962 if (ztype_class(old_ztype) == In_use_zone) { /* trouble */
963 if (new_indnum == old_indnum && new_ztype == old_ztype) {
964 fprintf(stderr, "WARNING: file system corrupt, zone block %ld \
965 is used more than once.\n", blknum);
966 return;
968 fprintf(stderr, "ERROR: file system corrupt, zone block %ld is used \
969 more than once.\n", blknum);
970 fail("Can't determine its type");
972 assert(ztype_class(old_ztype) == Old_zone);
975 if (new_indnum != old_indnum) {
976 *dz |= IND_CONFLICT_BIT;
977 if (new_indnum > old_indnum) {
978 *dz &= ~INDIRECT_MASK;
979 *dz |= new_indnum;
982 if (new_ztype == T_MAYBE_OLD_DIR || old_ztype == T_MAYBE_OLD_DIR) {
983 *dz |= TYPE_CONFLICT_BIT;
984 *dz &= ~T_MASK;
985 *dz |= T_MAYBE_OLD_DIR;
990 static class_t ztype_class(ztype)
991 int ztype;
993 class_t class;
995 if (ztype == T_MAYBE_OLD_DIR || ztype == T_OLD_NON_DIR)
996 class = Old_zone;
997 else if (ztype == T_DIR || ztype == T_NON_DIR)
998 class = In_use_zone;
999 else
1000 class = Unused_zone;
1002 return class;
1006 static void fail(str)
1007 char *str;
1009 fprintf(stderr, "%s\n", str);
1010 exit(1);
1014 static unsigned int two_bytes(buf)
1015 char buf[2];
1017 unsigned char *ubuf = (unsigned char *) buf;
1019 if (big_endian_fs)
1020 return(ubuf[0] << 8) | ubuf[1];
1021 else
1022 return(ubuf[1] << 8) | ubuf[0];
1026 static long four_bytes(buf)
1027 char buf[4];
1029 unsigned char *ubuf = (unsigned char *) buf;
1030 register int r1, r2;
1032 if (big_endian_fs) {
1033 r1 = (ubuf[0] << 8) | ubuf[1];
1034 r2 = (ubuf[2] << 8) | ubuf[3];
1035 } else {
1036 r2 = (ubuf[1] << 8) | ubuf[0];
1037 r1 = (ubuf[3] << 8) | ubuf[2];
1039 return((long) r1 << 16) | r2;
1043 static void usage(arg0)
1044 char *arg0;
1046 fprintf(stderr, "usage: %s [-v] srcfs [destfs]\n", arg0);
1047 exit(2);