1 /* swapfs - swap a Minix file system Author: Niels C. Willems */
6 /* Swapfs, a program to convert V1 or V2 Minix file systems from big endian
7 byte order to little endian and vv.
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>
51 #define _PROTOTYPE(function, params) function params
53 #define _PROTOTYPE(function, params) function()
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 */
98 #define T_UNKNOWN 0x00
99 #define T_MAYBE_OLD_DIR 0x04
100 #define T_OLD_NON_DIR 0x08
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
108 #define IND_CONFLICT_BIT 0x40
109 #define TYPE_CONFLICT_BIT 0x80
111 #define DIR_ENTRY_SIZE 16
114 Unused_zone
, Old_zone
, In_use_zone
117 typedef unsigned long blockn_t
;
118 typedef unsigned int inodesn_t
;
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 */
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,
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 */
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,
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
,
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
,
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
));
217 parse_args_init_io(argc
, argv
);
219 rw_init_super(&super
);
220 init_dzmap(&dzmap
, super
.dzmap_size
);
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
);
236 static void parse_args_init_io(argc
, argv
)
249 for (i
= 1; i
< argc
; i
++) {
251 if (*str
!= '-') break;
253 case 'v': verbose_flag
= 1; 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]);
266 if (open(argv
[i
], O_RDONLY
) != 0) {
267 fprintf(stderr
, "Can't open input file %s", argv
[i
]);
271 if (isatty(1) || argc
- i
== 2) {
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
]);
285 } else if (creat(argv
[i
], 0644) != 1) {
286 fprintf(stderr
, "Can't creat output file %s", argv
[i
]);
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");
304 static void rw_init_super(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
);
321 static void init_dzmap(dzmap_ptr
, 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
)
334 char ibuf
[BLOCK_SIZE
], obuf
[BLOCK_SIZE
];
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
);
346 static void rw_zbmap(super
)
349 char ibuf
[BLOCK_SIZE
], obuf
[BLOCK_SIZE
];
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
);
361 static void p1_rw_inodes(dzmap
, super
)
365 char buf
[BLOCK_SIZE
], *buf_ptr
;
366 inodesn_t i
, num_inodes
;
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");
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
)
396 register unsigned char dz
;
397 int both_conflict
= 0, ind_conflict
= 0, type_conflict
= 0, unreferenced
= 0;
400 if (!verbose_flag
) return;
402 for (i
= 0; i
< super
.dzmap_size
; i
++) {
404 if (dz
& IND_CONFLICT_BIT
&& dz
& TYPE_CONFLICT_BIT
)
406 else if (dz
& IND_CONFLICT_BIT
)
408 else if (dz
& TYPE_CONFLICT_BIT
)
411 if (dz
== 0) unreferenced
++;
412 if (ztype_class(dz
& T_MASK
) < In_use_zone
) not_in_use
++;
416 fprintf(stderr
, "%5d zone blocks with conflicting indir.\n",
418 fprintf(stderr
, "%5d zone blocks with conflicting types.\n",
420 fprintf(stderr
, "%5d zone blocks with conflicting types and indir.\n",
422 fprintf(stderr
, "%5d zone blocks never referenced.\n", unreferenced
);
424 fprintf(stderr
, "%5d zone blocks not in use.\n", not_in_use
);
429 static void rd_indirects(dzmap
, super
, ind
, required_class
)
433 class_t required_class
;
438 char buf
[BLOCK_SIZE
];
440 dz_offset
= super
.firstdatazone
;
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
))
449 if (read_block(buf
, dz_offset
+ i
) != BLOCK_SIZE
) {
450 fprintf(stderr
, "Can't read %s block", ind_str
[ind
]);
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
)
464 char ibuf
[BLOCK_SIZE
], obuf
[BLOCK_SIZE
];
466 int ztype
, ind
, last_read
;
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
;
476 ztype
= dzmap
[i
] & T_MASK
;
482 if (super
.version
== 1)
483 conv2_blkcpy(obuf
, ibuf
);
485 conv4_blkcpy(obuf
, ibuf
);
488 if (verbose_flag
&& i
&& i
% 1024 == 0) {
489 fprintf(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
)
505 static blockn_t curr_offset
= 0;
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
;
522 static void write_block(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
)
541 for (i
= 0; format
[i
] > 0; i
++) {
543 case 1: *dst
++ = *src
++; break;
560 fail("wrong format array for convcpy");
563 return(src
- old_src
);
567 static void conv2_blkcpy(dst
, src
)
574 for (i
= 0; i
< BLOCK_SIZE
; i
+= 2) {
582 static void conv4_blkcpy(dst
, src
)
589 for (i
= 0; i
< BLOCK_SIZE
; i
+= 4) {
604 static void conv2cpy(dst
, src
)
615 static int inode_size(version
)
618 return(version
== 1) ? V1_INODE_SIZE
: V2_INODE_SIZE
;
622 static void init_super(sp
, buf
)
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
) {
634 magic
= two_bytes(buf
+ MAGIC_OFFSET
);
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
);
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
;
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
)
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
);
694 for (i
= 0; i
< NR_DIRECT_ZONES
; i
++)
695 ip
->direct
[i
] = two_bytes(buf
+ INODE1_DIRECT_OFF
+ 2 * i
);
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
);
707 if (ip
->size
% DIR_ENTRY_SIZE
== 0)
708 ip
->ztype
= T_MAYBE_OLD_DIR
;
710 ip
->ztype
= T_OLD_NON_DIR
;
711 if (was_blk_special(*ip
)) ip
->size
= 0;
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
)
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
)
740 if (num
== 0 || (num
>= super
.firstdatazone
&& num
< super
.zones
))
743 fprintf(stderr
, "warning bad block number %ld in inode.\n", num
);
748 static int was_blk_special(inode
)
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
);
769 static void cw_inode_block(buf
, ninodes
, version
)
774 char output_buf
[BLOCK_SIZE
];
783 format
= (version
== 1) ? inode1_format
: inode2_format
;
784 for (i
= 0; i
< ninodes
; i
++) {
785 cnt
= convcpy(dst
, src
, format
);
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
)
812 int indnum
, i
, ztype
;
813 int word_size
; /* size of zone block number in ind. block in
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;
820 dz
= dzmap
[curr_ind
];
821 indnum
= dz
& INDIRECT_MASK
;
823 ind_blk
= curr_ind
+ super
.firstdatazone
;
825 word_size
= (super
.version
== 1) ? 2 : 4;
828 for (i
= 0; i
< BLOCK_SIZE
; i
+= word_size
) {
830 blk
= two_bytes(buf
+ i
);
832 blk
= four_bytes(buf
+ i
);
836 else if (blk
< super
.firstdatazone
|| blk
>= super
.zones
)
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
) {
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");
859 dzmap
[curr_ind
] &= ~(INDIRECT_MASK
& IND_CONFLICT_BIT
);
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
) {
869 blk
= two_bytes(buf
+ i
);
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
);
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
)
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
);
903 old_ino_offset
= i
+ DIR_ENTRY_SIZE
- 2;
904 conv2cpy(output_buf
+ old_ino_offset
, buf
+ old_ino_offset
);
906 conv2cpy(output_buf
+ i
, buf
+ i
);
908 write_block(output_buf
);
912 static void dzmap_add_inode(dzmap
, inode
, super
)
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
)
944 if (blknum
== 0) return;
946 dznum
= (size_t) (blknum
- super
.firstdatazone
);
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
)) {
957 } else if (ztype_class(new_ztype
) < ztype_class(old_ztype
))
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
);
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
;
982 if (new_ztype
== T_MAYBE_OLD_DIR
|| old_ztype
== T_MAYBE_OLD_DIR
) {
983 *dz
|= TYPE_CONFLICT_BIT
;
985 *dz
|= T_MAYBE_OLD_DIR
;
990 static class_t
ztype_class(ztype
)
995 if (ztype
== T_MAYBE_OLD_DIR
|| ztype
== T_OLD_NON_DIR
)
997 else if (ztype
== T_DIR
|| ztype
== T_NON_DIR
)
1000 class = Unused_zone
;
1006 static void fail(str
)
1009 fprintf(stderr
, "%s\n", str
);
1014 static unsigned int two_bytes(buf
)
1017 unsigned char *ubuf
= (unsigned char *) buf
;
1020 return(ubuf
[0] << 8) | ubuf
[1];
1022 return(ubuf
[1] << 8) | ubuf
[0];
1026 static long four_bytes(buf
)
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];
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
)
1046 fprintf(stderr
, "usage: %s [-v] srcfs [destfs]\n", arg0
);