source: trunk/minix/commands/simple/swapfs.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 25.0 KB
Line 
1/* swapfs - swap a Minix file system Author: Niels C. Willems */
2
3
4/* $Id: swapfs.c,v 1.1.1.1 2005/04/21 14:55:33 beng Exp $ */
5
6/* Swapfs, a program to convert V1 or V2 Minix file systems from big endian
7 byte order to little endian and vv.
8
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.
13
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
17
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
21
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.
25
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.
30
31 In this version you can get some more information about the
32 file system with the -d (debug) flag.
33
34 Please send your bug reports or ideas to ncwille@cs.vu.nl
35 */
36
37
38#define _POSIX_SOURCE 1
39
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>
47
48#include <assert.h>
49
50#if __STDC__ == 1
51#define _PROTOTYPE(function, params) function params
52#else
53#define _PROTOTYPE(function, params) function()
54#endif
55
56#define BLOCK_SIZE 1024
57
58#define BOOT_BLOCK_OFF (blockn_t) 0
59#define SUPER_BLOCK_OFF (blockn_t) 1
60
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
71
72
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
78
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
84
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
91
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 */
96
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
103
104#define INDIRECT_MASK 0x03
105
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
110
111#define DIR_ENTRY_SIZE 16
112
113typedef enum {
114 Unused_zone, Old_zone, In_use_zone
115} class_t;
116
117typedef unsigned long blockn_t;
118typedef unsigned int inodesn_t;
119
120typedef 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 */
127
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;
135
136
137typedef 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;
146
147static char rcsid[] = "$Id: swapfs.c,v 1.1.1.1 2005/04/21 14:55:33 beng Exp $";
148
149static int super_format[] = {2, 2, 2, 2, 2, 2, 4, 2, 2, 4, 0};
150static int inode1_format[] = {2, 2, 4, 4, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0};
151static int inode2_format[] = {2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
152 4, 4, 0};
153
154static char *ind_str[4] = {"direct", "single indirect",
155 "double indirect", "triple indirect"};
156
157static int big_endian_fs; /* set in init_super(), 1 iff file system has
158 * big endian byte order */
159static int verbose_flag;
160static int debug_flag;
161static int test_flag;
162
163typedef unsigned char *dzmap_t;
164
165
166int _PROTOTYPE(main, (int argc, char *argv[]));
167static void _PROTOTYPE(parse_args_init_io, (int argc, char *argv[]));
168static void _PROTOTYPE(rw_boot, (void));
169static void _PROTOTYPE(rw_init_super, (super_t * sp));
170static void _PROTOTYPE(init_dzmap, (dzmap_t * dzmap_ptr, size_t dzmap_size));
171static void _PROTOTYPE(rw_ibmap, (super_t super));
172static void _PROTOTYPE(rw_zbmap, (super_t super));
173static void _PROTOTYPE(print_stat, (dzmap_t dzmap, super_t super));
174static void _PROTOTYPE(p1_rw_inodes, (dzmap_t dzmap, super_t super));
175static void _PROTOTYPE(rd_indirects, (dzmap_t dzmap, super_t super, int ind,
176 class_t required_class));
177static void _PROTOTYPE(rw_data_zones, (dzmap_t dzmap, super_t super));
178
179static int _PROTOTYPE(read_block, (char *buf, blockn_t offset));
180static void _PROTOTYPE(write_block, (char *buf));
181static int _PROTOTYPE(convcpy, (char *dst, char *src, int *format));
182static void _PROTOTYPE(conv2_blkcpy, (char *dst, char *src));
183static void _PROTOTYPE(conv4_blkcpy, (char *dst, char *src));
184static void _PROTOTYPE(conv2cpy, (char *dst, char *src));
185static int _PROTOTYPE(inode_size, (int version));
186
187static void _PROTOTYPE(init_super, (super_t * sp, char *buf));
188static void _PROTOTYPE(get_inode, (inode_t * ip, char *buf, int version));
189static int _PROTOTYPE(check_inode, (inode_t inode, super_t super));
190static int _PROTOTYPE(was_blk_special, (inode_t inode));
191static int _PROTOTYPE(check_blk_number, (blockn_t num, super_t super));
192static void _PROTOTYPE(cw_inode_block, (char *buf, inodesn_t ninodes,
193 int version));
194static void _PROTOTYPE(proc_ind, (dzmap_t dzmap, size_t curr_ind,
195 char *buf, super_t super));
196static void _PROTOTYPE(cw_dir_block, (char *buf));
197static void _PROTOTYPE(dzmap_add_inode, (dzmap_t dzmap, inode_t inode,
198 super_t super));
199static void _PROTOTYPE(dz_update, (dzmap_t dzmap, blockn_t blknum,
200 int new_indnum, int new_ztype, super_t super));
201static class_t _PROTOTYPE(ztype_class, (int ztype));
202
203static unsigned int _PROTOTYPE(two_bytes, (char buf[2]));
204static long _PROTOTYPE(four_bytes, (char buf[4]));
205
206static void _PROTOTYPE(fail, (char *string));
207static void _PROTOTYPE(usage, (char *arg0));
208
209
210int main(argc, argv)
211int argc;
212char *argv[];
213{
214 super_t super;
215 dzmap_t dzmap;
216
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);
224
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);
229
230 print_stat(dzmap, super);
231 rw_data_zones(dzmap, super);
232 return 0;
233}
234
235
236static void parse_args_init_io(argc, argv)
237int argc;
238char *argv[];
239{
240 char *str;
241 struct stat buf;
242 ino_t src_ino;
243 int i;
244
245 debug_flag = 0;
246 verbose_flag = 0;
247 test_flag = 0;
248
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]);
260 }
261 }
262 if ((argc - i == 0 && isatty(0)) || (argc - i) > 2) usage(argv[0]);
263
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("");
269 }
270 }
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("");
284 }
285 } else if (creat(argv[i], 0644) != 1) {
286 fprintf(stderr, "Can't creat output file %s", argv[i]);
287 fail("");
288 }
289 }
290 }
291}
292
293
294static void rw_boot()
295{
296 char buf[BLOCK_SIZE];
297
298 if (read_block(buf, BOOT_BLOCK_OFF) != BLOCK_SIZE)
299 fail("Can't read bootblock");
300 write_block(buf);
301}
302
303
304static void rw_init_super(sp)
305super_t *sp;
306{
307 char ibuf[BLOCK_SIZE], obuf[BLOCK_SIZE];
308
309 if (read_block(ibuf, SUPER_BLOCK_OFF) != BLOCK_SIZE)
310 fail("Can't read superblock");
311
312 init_super(sp, ibuf);
313
314 memcpy(obuf, ibuf, (size_t) BLOCK_SIZE); /* preserve 'unused' data */
315 (void) convcpy(obuf, ibuf, super_format);
316
317 write_block(obuf);
318}
319
320
321static void init_dzmap(dzmap_ptr, dzmap_size)
322dzmap_t *dzmap_ptr;
323size_t dzmap_size;
324{
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);
328}
329
330
331static void rw_ibmap(super)
332super_t super;
333{
334 char ibuf[BLOCK_SIZE], obuf[BLOCK_SIZE];
335 blockn_t i;
336
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);
342 }
343}
344
345
346static void rw_zbmap(super)
347super_t super;
348{
349 char ibuf[BLOCK_SIZE], obuf[BLOCK_SIZE];
350 blockn_t i;
351
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);
357 }
358}
359
360
361static void p1_rw_inodes(dzmap, super)
362dzmap_t dzmap;
363super_t super;
364{
365 char buf[BLOCK_SIZE], *buf_ptr;
366 inodesn_t i, num_inodes;
367 blockn_t next_block;
368 inode_t inode;
369
370
371 next_block = super.first_inode_block;
372
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);
383 }
384 get_inode(&inode, buf_ptr, super.version);
385 dzmap_add_inode(dzmap, inode, super);
386 buf_ptr += inode_size(super.version);
387 }
388}
389
390
391static void print_stat(dzmap, super)
392dzmap_t dzmap;
393super_t super;
394{
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;
399
400 if (!verbose_flag) return;
401
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++;
410
411 if (dz == 0) unreferenced++;
412 if (ztype_class(dz & T_MASK) < In_use_zone) not_in_use++;
413
414 }
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);
423 }
424 fprintf(stderr, "%5d zone blocks not in use.\n", not_in_use);
425 putc('\n', stderr);
426}
427
428
429static void rd_indirects(dzmap, super, ind, required_class)
430dzmap_t dzmap;
431super_t super;
432int ind;
433class_t required_class;
434{
435 size_t i;
436 int ind_cnt;
437 off_t dz_offset;
438 char buf[BLOCK_SIZE];
439
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;
447
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("");
452 }
453 proc_ind(dzmap, i, buf, super);
454 }
455 if ((verbose_flag && ind_cnt > 0) || debug_flag)
456 fprintf(stderr, "%5d %s zone blocks.\n", ind_cnt, ind_str[ind]);
457}
458
459
460static void rw_data_zones(dzmap, super)
461dzmap_t dzmap;
462super_t super;
463{
464 char ibuf[BLOCK_SIZE], obuf[BLOCK_SIZE];
465 size_t i;
466 int ztype, ind, last_read;
467 off_t dz_offset;
468
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;
473
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);
487 }
488 if (verbose_flag && i && i % 1024 == 0) {
489 fprintf(stderr, ".");
490 fflush(stderr);
491 }
492 }
493 if (verbose_flag && i > 1024) putc('\n', stderr);
494
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");
498}
499
500
501static int read_block(buf, offset)
502char *buf;
503blockn_t offset;
504{
505 static blockn_t curr_offset = 0;
506 int bytes;
507
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;
512 }
513 bytes = read(0, buf, BLOCK_SIZE);
514 if (bytes < 0) fail("read failed on input file");
515
516 curr_offset += bytes;
517
518 return bytes;
519}
520
521
522static void write_block(buf)
523char *buf;
524{
525 if (test_flag) return;
526
527 if (write(1, buf, BLOCK_SIZE) != BLOCK_SIZE)
528 fail("write failed on output file");
529}
530
531
532static int convcpy(dst, src, format)
533char *dst;
534char *src;
535int *format;
536{
537 char *old_src = src;
538 register char tmp;
539 int i;
540
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");
561 }
562 }
563 return(src - old_src);
564}
565
566
567static void conv2_blkcpy(dst, src)
568char *dst;
569char *src;
570{
571 int i;
572 register char tmp;
573
574 for (i = 0; i < BLOCK_SIZE; i += 2) {
575 tmp = *src++;
576 *dst++ = *src++;
577 *dst++ = tmp;
578 }
579}
580
581
582static void conv4_blkcpy(dst, src)
583char *dst;
584char *src;
585{
586 int i;
587 register char tmp;
588
589 for (i = 0; i < BLOCK_SIZE; i += 4) {
590 tmp = src[0];
591 dst[0] = src[3];
592 dst[3] = tmp;
593
594 tmp = src[1];
595 dst[1] = src[2];
596 dst[2] = tmp;
597
598 src += 4;
599 dst += 4;
600 }
601}
602
603
604static void conv2cpy(dst, src)
605char *dst;
606char *src;
607{
608 register char tmp;
609 tmp = *src++;
610 *dst++ = *src++;
611 *dst++ = tmp;
612}
613
614
615static int inode_size(version)
616int version;
617{
618 return(version == 1) ? V1_INODE_SIZE : V2_INODE_SIZE;
619}
620
621
622static void init_super(sp, buf)
623super_t *sp;
624char *buf;
625{
626 int magic;
627 long imapblks, zmapblks;
628
629 big_endian_fs = 0; /* guess the file system is little endian */
630 magic = two_bytes(buf + MAGIC_OFFSET);
631
632 if (magic != V1_MAGIC && magic != V2_MAGIC) {
633 big_endian_fs = 1;
634 magic = two_bytes(buf + MAGIC_OFFSET);
635 }
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");
640}
641
642 if (verbose_flag) fprintf(stderr, "\nVersion = V%d, %s endian.\n",
643 sp->version, big_endian_fs ? "big" : "little");
644
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);
652
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);
657
658 sp->inodes_per_block = BLOCK_SIZE / inode_size(sp->version);
659
660 if (imapblks < 0 || zmapblks < 0 || sp->ninodes < 1 || sp->zones < 1)
661 fail("Bad superblock");
662
663
664 if (sp->log_zone_size != 0)
665 fail("Can't swap file systems with different zone and block sizes");
666
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;
670
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);
676 }
677}
678
679
680static void get_inode(ip, buf, version)
681inode_t *ip;
682char *buf;
683int version;
684{
685 int i;
686 int mode;
687
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);
704 }
705
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;
717 }
718}
719
720
721static int check_inode(inode, super)
722inode_t inode;
723super_t super;
724{
725 int i;
726
727 for (i = 0; i < NR_DIRECT_ZONES; i++)
728 if (!check_blk_number(inode.direct[i], super)) return 0;
729
730 return(check_blk_number(inode.ind1, super) &&
731 check_blk_number(inode.ind2, super) &&
732 check_blk_number(inode.ind3, super));
733}
734
735
736static int check_blk_number(num, super)
737blockn_t num;
738super_t super;
739{
740 if (num == 0 || (num >= super.firstdatazone && num < super.zones))
741 return 1;
742
743 fprintf(stderr, "warning bad block number %ld in inode.\n", num);
744 return 0;
745}
746
747
748static int was_blk_special(inode)
749inode_t inode;
750{
751 int i, result;
752 blockn_t block_size;
753
754 if (inode.size % BLOCK_SIZE || inode.ind1) return 0;
755 block_size = inode.size / BLOCK_SIZE;
756
757 for (i = NR_DIRECT_ZONES - 1; i >= 0; i--)
758 if (inode.direct[i] != 0) break;
759
760 result = (i < 1 && block_size > i + 1);
761
762 if (debug_flag && result) {
763 fprintf(stderr, "old block special file detected (slot = %d).\n", i);
764 }
765 return result;
766}
767
768
769static void cw_inode_block(buf, ninodes, version)
770char *buf;
771inodesn_t ninodes;
772int version;
773{
774 char output_buf[BLOCK_SIZE];
775 char *src, *dst;
776 inodesn_t i;
777 int cnt, free_bytes;
778 int *format;
779
780 src = buf;
781 dst = output_buf;
782
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;
788 }
789
790 assert(cnt == inode_size(version));
791
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);
801 }
802 write_block(output_buf);
803}
804
805
806static void proc_ind(dzmap, curr_ind, buf, super)
807dzmap_t dzmap;
808size_t curr_ind;
809char *buf;
810super_t super;
811{
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;
819
820 dz = dzmap[curr_ind];
821 indnum = dz & INDIRECT_MASK;
822 ztype = dz & T_MASK;
823 ind_blk = curr_ind + super.firstdatazone;
824
825 word_size = (super.version == 1) ? 2 : 4;
826 assert(indnum > 0);
827
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);
833
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;
843 }
844
845 }
846
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");
851 }
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");
856 }
857 } else {
858 if (expired) {
859 dzmap[curr_ind] &= ~(INDIRECT_MASK & IND_CONFLICT_BIT);
860 return;
861 }
862
863 /* Not yet implemented. :-( if (bad_range || (indnum > 1 &&
864 * hidden_zero) || equal_values(buf, super.version ) { } */
865 }
866
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);
872
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 \
880than once\n", ind_str[indnum - 1], blk);
881 else {
882 fprintf(stderr, "Block %ld used more than ", blk);
883 fail("once with different types");
884 }
885 }
886 dzmap[blk_index] = (dz & ~INDIRECT_MASK) | (indnum - 1);
887 }
888 dzmap[curr_ind] |= IND_PROCESSED_BIT;
889}
890
891
892static void cw_dir_block(buf)
893char *buf;
894{
895 char output_buf[BLOCK_SIZE];
896 int ino, i, old_ino_offset;
897
898 memcpy(output_buf, buf, BLOCK_SIZE);
899
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);
907 }
908 write_block(output_buf);
909}
910
911
912static void dzmap_add_inode(dzmap, inode, super)
913dzmap_t dzmap;
914inode_t inode;
915super_t super;
916{
917 int i;
918
919 if (inode.size == 0 || !check_inode(inode, super)) return;
920
921 for (i = 0; i < NR_DIRECT_ZONES; i++)
922 dz_update(dzmap, inode.direct[i], 0, inode.ztype, super);
923
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);
927}
928
929
930static void dz_update(dzmap, blknum, new_indnum, new_ztype, super)
931dzmap_t dzmap;
932blockn_t blknum;
933int new_indnum;
934int new_ztype;
935super_t super;
936{
937 size_t dznum;
938 int old_indnum;
939 int old_ztype;
940 unsigned char *dz;
941 char new_dz;
942
943
944 if (blknum == 0) return;
945
946 dznum = (size_t) (blknum - super.firstdatazone);
947
948 dz = &dzmap[dznum];
949 old_indnum = *dz & INDIRECT_MASK;
950 old_ztype = *dz & T_MASK;
951
952 new_dz = new_ztype | new_indnum;
953
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;
959
960 /* Collision: old and new have the same class */
961
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 \
965is used more than once.\n", blknum);
966 return;
967 }
968 fprintf(stderr, "ERROR: file system corrupt, zone block %ld is used \
969more than once.\n", blknum);
970 fail("Can't determine its type");
971 }
972 assert(ztype_class(old_ztype) == Old_zone);
973
974
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;
980 }
981 }
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;
986 }
987}
988
989
990static class_t ztype_class(ztype)
991int ztype;
992{
993 class_t class;
994
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;
1001
1002 return class;
1003}
1004
1005
1006static void fail(str)
1007char *str;
1008{
1009 fprintf(stderr, "%s\n", str);
1010 exit(1);
1011}
1012
1013
1014static unsigned int two_bytes(buf)
1015char buf[2];
1016{
1017 unsigned char *ubuf = (unsigned char *) buf;
1018
1019 if (big_endian_fs)
1020 return(ubuf[0] << 8) | ubuf[1];
1021 else
1022 return(ubuf[1] << 8) | ubuf[0];
1023}
1024
1025
1026static long four_bytes(buf)
1027char buf[4];
1028{
1029 unsigned char *ubuf = (unsigned char *) buf;
1030 register int r1, r2;
1031
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];
1038 }
1039 return((long) r1 << 16) | r2;
1040}
1041
1042
1043static void usage(arg0)
1044char *arg0;
1045{
1046 fprintf(stderr, "usage: %s [-v] srcfs [destfs]\n", arg0);
1047 exit(2);
1048}
Note: See TracBrowser for help on using the repository browser.