00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #define _POSIX_SOURCE 1
00039
00040 #include <sys/types.h>
00041 #include <sys/stat.h>
00042 #include <stdlib.h>
00043 #include <fcntl.h>
00044 #include <string.h>
00045 #include <unistd.h>
00046 #include <stdio.h>
00047
00048 #include <assert.h>
00049
00050 #if __STDC__ == 1
00051 #define _PROTOTYPE(function, params) function params
00052 #else
00053 #define _PROTOTYPE(function, params) function()
00054 #endif
00055
00056 #define BLOCK_SIZE 1024
00057
00058 #define BOOT_BLOCK_OFF (blockn_t) 0
00059 #define SUPER_BLOCK_OFF (blockn_t) 1
00060
00061 #define V1_MAGIC 0x137F
00062 #define V2_MAGIC 0x2468
00063 #define NINODES_OFFSET 0
00064 #define V1_ZONES_OFFSET 2
00065 #define IMAP_BLOCKS_OFFSET 4
00066 #define ZMAP_BLOCKS_OFFSET 6
00067 #define FIRSTDATAZONE_OFFSET 8
00068 #define LOG_ZONE_SIZE_OFFSET 10
00069 #define MAGIC_OFFSET 16
00070 #define V2_ZONES_OFFSET 20
00071
00072
00073 #define NR_DIRECT_ZONES 7
00074 #define V1_NR_TZONES 9
00075 #define V2_NR_TZONES 10
00076 #define V1_INODE_SIZE 32
00077 #define V2_INODE_SIZE 64
00078
00079 #define INODE1_MODE_OFF 0
00080 #define INODE1_SIZE_OFF 4
00081 #define INODE1_DIRECT_OFF 14
00082 #define INODE1_IND1_OFF 28
00083 #define INODE1_IND2_OFF 30
00084
00085 #define INODE2_MODE_OFF 0
00086 #define INODE2_SIZE_OFF 8
00087 #define INODE2_DIRECT_OFF 24
00088 #define INODE2_IND1_OFF 52
00089 #define INODE2_IND2_OFF 56
00090 #define INODE2_IND3_OFF 60
00091
00092 #define INODE_MODE_MASK 0xf000
00093 #define INODE_DIR_MODE 0x4000
00094 #define INODE_BLK_SPECIAL_MODE 0x6000
00095 #define INODE_CHR_SPECIAL_MODE 0x2000
00096
00097 #define T_MASK 0x1c
00098 #define T_UNKNOWN 0x00
00099 #define T_MAYBE_OLD_DIR 0x04
00100 #define T_OLD_NON_DIR 0x08
00101 #define T_DIR 0x0c
00102 #define T_NON_DIR 0x10
00103
00104 #define INDIRECT_MASK 0x03
00105
00106 #define IND_PROCESSED_BIT 0x20
00107
00108 #define IND_CONFLICT_BIT 0x40
00109 #define TYPE_CONFLICT_BIT 0x80
00110
00111 #define DIR_ENTRY_SIZE 16
00112
00113 typedef enum {
00114 Unused_zone, Old_zone, In_use_zone
00115 } class_t;
00116
00117 typedef unsigned long blockn_t;
00118 typedef unsigned int inodesn_t;
00119
00120 typedef struct {
00121 inodesn_t ninodes;
00122 blockn_t imap_blocks;
00123 blockn_t zmap_blocks;
00124 blockn_t firstdatazone;
00125 int log_zone_size;
00126 blockn_t zones;
00127
00128 int version;
00129 inodesn_t inodes_per_block;
00130 blockn_t first_imap_block;
00131 blockn_t first_zmap_block;
00132 blockn_t first_inode_block;
00133 size_t dzmap_size;
00134 } super_t;
00135
00136
00137 typedef struct {
00138 long size;
00139 blockn_t direct[NR_DIRECT_ZONES];
00140
00141 blockn_t ind1;
00142 blockn_t ind2;
00143 blockn_t ind3;
00144 int ztype;
00145 } inode_t;
00146
00147 static char rcsid[] = "$Id: swapfs.c 5628 2009-11-09 10:26:00Z thruby $";
00148
00149 static int super_format[] = {2, 2, 2, 2, 2, 2, 4, 2, 2, 4, 0};
00150 static int inode1_format[] = {2, 2, 4, 4, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0};
00151 static int inode2_format[] = {2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
00152 4, 4, 0};
00153
00154 static char *ind_str[4] = {"direct", "single indirect",
00155 "double indirect", "triple indirect"};
00156
00157 static int big_endian_fs;
00158
00159 static int verbose_flag;
00160 static int debug_flag;
00161 static int test_flag;
00162
00163 typedef unsigned char *dzmap_t;
00164
00165
00166 int _PROTOTYPE(main, (int argc, char *argv[]));
00167 static void _PROTOTYPE(parse_args_init_io, (int argc, char *argv[]));
00168 static void _PROTOTYPE(rw_boot, (void));
00169 static void _PROTOTYPE(rw_init_super, (super_t * sp));
00170 static void _PROTOTYPE(init_dzmap, (dzmap_t * dzmap_ptr, size_t dzmap_size));
00171 static void _PROTOTYPE(rw_ibmap, (super_t super));
00172 static void _PROTOTYPE(rw_zbmap, (super_t super));
00173 static void _PROTOTYPE(print_stat, (dzmap_t dzmap, super_t super));
00174 static void _PROTOTYPE(p1_rw_inodes, (dzmap_t dzmap, super_t super));
00175 static void _PROTOTYPE(rd_indirects, (dzmap_t dzmap, super_t super, int ind,
00176 class_t required_class));
00177 static void _PROTOTYPE(rw_data_zones, (dzmap_t dzmap, super_t super));
00178
00179 static int _PROTOTYPE(read_block, (char *buf, blockn_t offset));
00180 static void _PROTOTYPE(write_block, (char *buf));
00181 static int _PROTOTYPE(convcpy, (char *dst, char *src, int *format));
00182 static void _PROTOTYPE(conv2_blkcpy, (char *dst, char *src));
00183 static void _PROTOTYPE(conv4_blkcpy, (char *dst, char *src));
00184 static void _PROTOTYPE(conv2cpy, (char *dst, char *src));
00185 static int _PROTOTYPE(inode_size, (int version));
00186
00187 static void _PROTOTYPE(init_super, (super_t * sp, char *buf));
00188 static void _PROTOTYPE(get_inode, (inode_t * ip, char *buf, int version));
00189 static int _PROTOTYPE(check_inode, (inode_t inode, super_t super));
00190 static int _PROTOTYPE(was_blk_special, (inode_t inode));
00191 static int _PROTOTYPE(check_blk_number, (blockn_t num, super_t super));
00192 static void _PROTOTYPE(cw_inode_block, (char *buf, inodesn_t ninodes,
00193 int version));
00194 static void _PROTOTYPE(proc_ind, (dzmap_t dzmap, size_t curr_ind,
00195 char *buf, super_t super));
00196 static void _PROTOTYPE(cw_dir_block, (char *buf));
00197 static void _PROTOTYPE(dzmap_add_inode, (dzmap_t dzmap, inode_t inode,
00198 super_t super));
00199 static void _PROTOTYPE(dz_update, (dzmap_t dzmap, blockn_t blknum,
00200 int new_indnum, int new_ztype, super_t super));
00201 static class_t _PROTOTYPE(ztype_class, (int ztype));
00202
00203 static unsigned int _PROTOTYPE(two_bytes, (char buf[2]));
00204 static long _PROTOTYPE(four_bytes, (char buf[4]));
00205
00206 static void _PROTOTYPE(fail, (char *string));
00207 static void _PROTOTYPE(usage, (char *arg0));
00208
00209
00210 int main(argc, argv)
00211 int argc;
00212 char *argv[];
00213 {
00214 super_t super;
00215 dzmap_t dzmap;
00216
00217 parse_args_init_io(argc, argv);
00218 rw_boot();
00219 rw_init_super(&super);
00220 init_dzmap(&dzmap, super.dzmap_size);
00221 rw_ibmap(super);
00222 rw_zbmap(super);
00223 p1_rw_inodes(dzmap, super);
00224
00225 rd_indirects(dzmap, super, 3, In_use_zone);
00226 rd_indirects(dzmap, super, 2, In_use_zone);
00227 rd_indirects(dzmap, super, 1, In_use_zone);
00228 if (verbose_flag) putc('\n', stderr);
00229
00230 print_stat(dzmap, super);
00231 rw_data_zones(dzmap, super);
00232 return 0;
00233 }
00234
00235
00236 static void parse_args_init_io(argc, argv)
00237 int argc;
00238 char *argv[];
00239 {
00240 char *str;
00241 struct stat buf;
00242 ino_t src_ino;
00243 int i;
00244
00245 debug_flag = 0;
00246 verbose_flag = 0;
00247 test_flag = 0;
00248
00249 for (i = 1; i < argc; i++) {
00250 str = argv[i];
00251 if (*str != '-') break;
00252 switch (*++str) {
00253 case 'v': verbose_flag = 1; break;
00254 case 'd':
00255 debug_flag = 1;
00256 verbose_flag = 1;
00257 break;
00258 case 't': test_flag = 1; break;
00259 default: usage(argv[0]);
00260 }
00261 }
00262 if ((argc - i == 0 && isatty(0)) || (argc - i) > 2) usage(argv[0]);
00263
00264 if (argc - i > 0) {
00265 (void) close(0);
00266 if (open(argv[i], O_RDONLY) != 0) {
00267 fprintf(stderr, "Can't open input file %s", argv[i]);
00268 fail("");
00269 }
00270 }
00271 if (isatty(1) || argc - i == 2) {
00272 if (argc - i < 2)
00273 test_flag = 1;
00274 else {
00275 i++;
00276 (void) close(1);
00277 (void) fstat(0, &buf);
00278 src_ino = buf.st_ino;
00279 if (stat(argv[i], &buf) == 0 && src_ino == buf.st_ino) {
00280
00281 if (open(argv[i], O_WRONLY) != 1) {
00282 fprintf(stderr, "Can't open output file %s", argv[i]);
00283 fail("");
00284 }
00285 } else if (creat(argv[i], 0644) != 1) {
00286 fprintf(stderr, "Can't creat output file %s", argv[i]);
00287 fail("");
00288 }
00289 }
00290 }
00291 }
00292
00293
00294 static void rw_boot()
00295 {
00296 char buf[BLOCK_SIZE];
00297
00298 if (read_block(buf, BOOT_BLOCK_OFF) != BLOCK_SIZE)
00299 fail("Can't read bootblock");
00300 write_block(buf);
00301 }
00302
00303
00304 static void rw_init_super(sp)
00305 super_t *sp;
00306 {
00307 char ibuf[BLOCK_SIZE], obuf[BLOCK_SIZE];
00308
00309 if (read_block(ibuf, SUPER_BLOCK_OFF) != BLOCK_SIZE)
00310 fail("Can't read superblock");
00311
00312 init_super(sp, ibuf);
00313
00314 memcpy(obuf, ibuf, (size_t) BLOCK_SIZE);
00315 (void) convcpy(obuf, ibuf, super_format);
00316
00317 write_block(obuf);
00318 }
00319
00320
00321 static void init_dzmap(dzmap_ptr, dzmap_size)
00322 dzmap_t *dzmap_ptr;
00323 size_t dzmap_size;
00324 {
00325 if ((*dzmap_ptr = (dzmap_t) malloc(dzmap_size)) == (dzmap_t) NULL)
00326 fail("Not enough space for data zone map");
00327 memset(*dzmap_ptr, '\0', (size_t) dzmap_size);
00328 }
00329
00330
00331 static void rw_ibmap(super)
00332 super_t super;
00333 {
00334 char ibuf[BLOCK_SIZE], obuf[BLOCK_SIZE];
00335 blockn_t i;
00336
00337 for (i = 0; i < super.imap_blocks; i++) {
00338 if (read_block(ibuf, super.first_imap_block + i) != BLOCK_SIZE)
00339 fail("Can't read inode bit map");
00340 conv2_blkcpy(obuf, ibuf);
00341 write_block(obuf);
00342 }
00343 }
00344
00345
00346 static void rw_zbmap(super)
00347 super_t super;
00348 {
00349 char ibuf[BLOCK_SIZE], obuf[BLOCK_SIZE];
00350 blockn_t i;
00351
00352 for (i = 0; i < super.zmap_blocks; i++) {
00353 if (read_block(ibuf, super.first_zmap_block + i) != BLOCK_SIZE)
00354 fail("Can't read zone bit map");
00355 conv2_blkcpy(obuf, ibuf);
00356 write_block(obuf);
00357 }
00358 }
00359
00360
00361 static void p1_rw_inodes(dzmap, super)
00362 dzmap_t dzmap;
00363 super_t super;
00364 {
00365 char buf[BLOCK_SIZE], *buf_ptr;
00366 inodesn_t i, num_inodes;
00367 blockn_t next_block;
00368 inode_t inode;
00369
00370
00371 next_block = super.first_inode_block;
00372
00373 for (i = 1; i <= super.ninodes; i++) {
00374 if ((i - 1) % super.inodes_per_block == 0) {
00375 if (read_block(buf, next_block) != BLOCK_SIZE)
00376 fail("read failed in inode block");
00377 buf_ptr = buf;
00378 next_block++;
00379 num_inodes = super.ninodes + 1 - i;
00380 if (num_inodes > super.inodes_per_block)
00381 num_inodes = super.inodes_per_block;
00382 cw_inode_block(buf, num_inodes, super.version);
00383 }
00384 get_inode(&inode, buf_ptr, super.version);
00385 dzmap_add_inode(dzmap, inode, super);
00386 buf_ptr += inode_size(super.version);
00387 }
00388 }
00389
00390
00391 static void print_stat(dzmap, super)
00392 dzmap_t dzmap;
00393 super_t super;
00394 {
00395 size_t i;
00396 register unsigned char dz;
00397 int both_conflict = 0, ind_conflict = 0, type_conflict = 0, unreferenced = 0;
00398 int not_in_use = 0;
00399
00400 if (!verbose_flag) return;
00401
00402 for (i = 0; i < super.dzmap_size; i++) {
00403 dz = dzmap[i];
00404 if (dz & IND_CONFLICT_BIT && dz & TYPE_CONFLICT_BIT)
00405 both_conflict++;
00406 else if (dz & IND_CONFLICT_BIT)
00407 ind_conflict++;
00408 else if (dz & TYPE_CONFLICT_BIT)
00409 type_conflict++;
00410
00411 if (dz == 0) unreferenced++;
00412 if (ztype_class(dz & T_MASK) < In_use_zone) not_in_use++;
00413
00414 }
00415 if (debug_flag) {
00416 fprintf(stderr, "%5d zone blocks with conflicting indir.\n",
00417 ind_conflict);
00418 fprintf(stderr, "%5d zone blocks with conflicting types.\n",
00419 type_conflict);
00420 fprintf(stderr, "%5d zone blocks with conflicting types and indir.\n",
00421 both_conflict);
00422 fprintf(stderr, "%5d zone blocks never referenced.\n", unreferenced);
00423 }
00424 fprintf(stderr, "%5d zone blocks not in use.\n", not_in_use);
00425 putc('\n', stderr);
00426 }
00427
00428
00429 static void rd_indirects(dzmap, super, ind, required_class)
00430 dzmap_t dzmap;
00431 super_t super;
00432 int ind;
00433 class_t required_class;
00434 {
00435 size_t i;
00436 int ind_cnt;
00437 off_t dz_offset;
00438 char buf[BLOCK_SIZE];
00439
00440 dz_offset = super.firstdatazone;
00441 ind_cnt = 0;
00442 for (i = 0; i < super.dzmap_size; i++) {
00443 if (ztype_class(dzmap[i] & T_MASK) != required_class ||
00444 (dzmap[i] & INDIRECT_MASK) != ind ||
00445 (dzmap[i] & IND_PROCESSED_BIT))
00446 continue;
00447
00448 ind_cnt++;
00449 if (read_block(buf, dz_offset + i) != BLOCK_SIZE) {
00450 fprintf(stderr, "Can't read %s block", ind_str[ind]);
00451 fail("");
00452 }
00453 proc_ind(dzmap, i, buf, super);
00454 }
00455 if ((verbose_flag && ind_cnt > 0) || debug_flag)
00456 fprintf(stderr, "%5d %s zone blocks.\n", ind_cnt, ind_str[ind]);
00457 }
00458
00459
00460 static void rw_data_zones(dzmap, super)
00461 dzmap_t dzmap;
00462 super_t super;
00463 {
00464 char ibuf[BLOCK_SIZE], obuf[BLOCK_SIZE];
00465 size_t i;
00466 int ztype, ind, last_read;
00467 off_t dz_offset;
00468
00469 dz_offset = super.firstdatazone;
00470 for (i = 0; i < super.dzmap_size; i++) {
00471 last_read = read_block(ibuf, dz_offset + i);
00472 if (last_read != BLOCK_SIZE) break;
00473
00474 ind = dzmap[i] & INDIRECT_MASK;
00475 if (ind == 0) {
00476 ztype = dzmap[i] & T_MASK;
00477 if (ztype == T_DIR)
00478 cw_dir_block(ibuf);
00479 else
00480 write_block(ibuf);
00481 } else {
00482 if (super.version == 1)
00483 conv2_blkcpy(obuf, ibuf);
00484 else
00485 conv4_blkcpy(obuf, ibuf);
00486 write_block(obuf);
00487 }
00488 if (verbose_flag && i && i % 1024 == 0) {
00489 fprintf(stderr, ".");
00490 fflush(stderr);
00491 }
00492 }
00493 if (verbose_flag && i > 1024) putc('\n', stderr);
00494
00495 if (last_read != BLOCK_SIZE) for (; i < super.dzmap_size; i++)
00496 if (ztype_class(dzmap[i] & T_MASK) == In_use_zone)
00497 fail("Can't read data zone");
00498 }
00499
00500
00501 static int read_block(buf, offset)
00502 char *buf;
00503 blockn_t offset;
00504 {
00505 static blockn_t curr_offset = 0;
00506 int bytes;
00507
00508 if (offset != curr_offset) {
00509 if (lseek(0, (off_t) offset * BLOCK_SIZE, 0) == -1)
00510 fail("lseek failed on input file");
00511 curr_offset = offset;
00512 }
00513 bytes = read(0, buf, BLOCK_SIZE);
00514 if (bytes < 0) fail("read failed on input file");
00515
00516 curr_offset += bytes;
00517
00518 return bytes;
00519 }
00520
00521
00522 static void write_block(buf)
00523 char *buf;
00524 {
00525 if (test_flag) return;
00526
00527 if (write(1, buf, BLOCK_SIZE) != BLOCK_SIZE)
00528 fail("write failed on output file");
00529 }
00530
00531
00532 static int convcpy(dst, src, format)
00533 char *dst;
00534 char *src;
00535 int *format;
00536 {
00537 char *old_src = src;
00538 register char tmp;
00539 int i;
00540
00541 for (i = 0; format[i] > 0; i++) {
00542 switch (format[i]) {
00543 case 1: *dst++ = *src++; break;
00544 case 2:
00545 tmp = *src++;
00546 *dst++ = *src++;
00547 *dst++ = tmp;
00548 break;
00549 case 4:
00550 tmp = src[0];
00551 dst[0] = src[3];
00552 dst[3] = tmp;
00553 tmp = src[1];
00554 dst[1] = src[2];
00555 dst[2] = tmp;
00556 src += 4;
00557 dst += 4;
00558 break;
00559 default:
00560 fail("wrong format array for convcpy");
00561 }
00562 }
00563 return(src - old_src);
00564 }
00565
00566
00567 static void conv2_blkcpy(dst, src)
00568 char *dst;
00569 char *src;
00570 {
00571 int i;
00572 register char tmp;
00573
00574 for (i = 0; i < BLOCK_SIZE; i += 2) {
00575 tmp = *src++;
00576 *dst++ = *src++;
00577 *dst++ = tmp;
00578 }
00579 }
00580
00581
00582 static void conv4_blkcpy(dst, src)
00583 char *dst;
00584 char *src;
00585 {
00586 int i;
00587 register char tmp;
00588
00589 for (i = 0; i < BLOCK_SIZE; i += 4) {
00590 tmp = src[0];
00591 dst[0] = src[3];
00592 dst[3] = tmp;
00593
00594 tmp = src[1];
00595 dst[1] = src[2];
00596 dst[2] = tmp;
00597
00598 src += 4;
00599 dst += 4;
00600 }
00601 }
00602
00603
00604 static void conv2cpy(dst, src)
00605 char *dst;
00606 char *src;
00607 {
00608 register char tmp;
00609 tmp = *src++;
00610 *dst++ = *src++;
00611 *dst++ = tmp;
00612 }
00613
00614
00615 static int inode_size(version)
00616 int version;
00617 {
00618 return(version == 1) ? V1_INODE_SIZE : V2_INODE_SIZE;
00619 }
00620
00621
00622 static void init_super(sp, buf)
00623 super_t *sp;
00624 char *buf;
00625 {
00626 int magic;
00627 long imapblks, zmapblks;
00628
00629 big_endian_fs = 0;
00630 magic = two_bytes(buf + MAGIC_OFFSET);
00631
00632 if (magic != V1_MAGIC && magic != V2_MAGIC) {
00633 big_endian_fs = 1;
00634 magic = two_bytes(buf + MAGIC_OFFSET);
00635 }
00636 switch (magic) {
00637 case V1_MAGIC: sp->version = 1; break;
00638 case V2_MAGIC: sp->version = 2; break;
00639 default: fail("Not a Minix file system");
00640 }
00641
00642 if (verbose_flag) fprintf(stderr, "\nVersion = V%d, %s endian.\n",
00643 sp->version, big_endian_fs ? "big" : "little");
00644
00645 sp->ninodes = two_bytes(buf + NINODES_OFFSET);
00646 imapblks = two_bytes(buf + IMAP_BLOCKS_OFFSET);
00647 sp->imap_blocks = imapblks;
00648 zmapblks = two_bytes(buf + ZMAP_BLOCKS_OFFSET);
00649 sp->zmap_blocks = zmapblks;
00650 sp->firstdatazone = two_bytes(buf + FIRSTDATAZONE_OFFSET);
00651 sp->log_zone_size = two_bytes(buf + LOG_ZONE_SIZE_OFFSET);
00652
00653 if (sp->version == 1)
00654 sp->zones = two_bytes(buf + V1_ZONES_OFFSET);
00655 else
00656 sp->zones = four_bytes(buf + V2_ZONES_OFFSET);
00657
00658 sp->inodes_per_block = BLOCK_SIZE / inode_size(sp->version);
00659
00660 if (imapblks < 0 || zmapblks < 0 || sp->ninodes < 1 || sp->zones < 1)
00661 fail("Bad superblock");
00662
00663
00664 if (sp->log_zone_size != 0)
00665 fail("Can't swap file systems with different zone and block sizes");
00666
00667 sp->first_imap_block = SUPER_BLOCK_OFF + 1;
00668 sp->first_zmap_block = sp->first_imap_block + sp->imap_blocks;
00669 sp->first_inode_block = sp->first_zmap_block + sp->zmap_blocks;
00670
00671 sp->dzmap_size = sp->zones - sp->firstdatazone;
00672 if (verbose_flag) {
00673 fprintf(stderr, "nzones = %ld, ", sp->zones);
00674 fprintf(stderr, "ninodes = %u, ", sp->ninodes);
00675 fprintf(stderr, "first data zone = %ld.\n\n", sp->firstdatazone);
00676 }
00677 }
00678
00679
00680 static void get_inode(ip, buf, version)
00681 inode_t *ip;
00682 char *buf;
00683 int version;
00684 {
00685 int i;
00686 int mode;
00687
00688 if (version == 1) {
00689 mode = two_bytes(buf + INODE1_MODE_OFF);
00690 ip->size = four_bytes(buf + INODE1_SIZE_OFF);
00691 ip->ind1 = two_bytes(buf + INODE1_IND1_OFF);
00692 ip->ind2 = two_bytes(buf + INODE1_IND2_OFF);
00693 ip->ind3 = 0;
00694 for (i = 0; i < NR_DIRECT_ZONES; i++)
00695 ip->direct[i] = two_bytes(buf + INODE1_DIRECT_OFF + 2 * i);
00696 } else {
00697 mode = two_bytes(buf + INODE2_MODE_OFF);
00698 ip->size = four_bytes(buf + INODE2_SIZE_OFF);
00699 ip->ind1 = four_bytes(buf + INODE2_IND1_OFF);
00700 ip->ind2 = four_bytes(buf + INODE2_IND2_OFF);
00701 ip->ind3 = four_bytes(buf + INODE2_IND3_OFF);
00702 for (i = 0; i < NR_DIRECT_ZONES; i++)
00703 ip->direct[i] = four_bytes(buf + INODE2_DIRECT_OFF + 4 * i);
00704 }
00705
00706 if (mode == 0) {
00707 if (ip->size % DIR_ENTRY_SIZE == 0)
00708 ip->ztype = T_MAYBE_OLD_DIR;
00709 else
00710 ip->ztype = T_OLD_NON_DIR;
00711 if (was_blk_special(*ip)) ip->size = 0;
00712 } else {
00713 mode = mode & INODE_MODE_MASK;
00714 if (mode == INODE_BLK_SPECIAL_MODE || mode == INODE_CHR_SPECIAL_MODE)
00715 ip->size = 0;
00716 ip->ztype = (mode == INODE_DIR_MODE) ? T_DIR : T_NON_DIR;
00717 }
00718 }
00719
00720
00721 static int check_inode(inode, super)
00722 inode_t inode;
00723 super_t super;
00724 {
00725 int i;
00726
00727 for (i = 0; i < NR_DIRECT_ZONES; i++)
00728 if (!check_blk_number(inode.direct[i], super)) return 0;
00729
00730 return(check_blk_number(inode.ind1, super) &&
00731 check_blk_number(inode.ind2, super) &&
00732 check_blk_number(inode.ind3, super));
00733 }
00734
00735
00736 static int check_blk_number(num, super)
00737 blockn_t num;
00738 super_t super;
00739 {
00740 if (num == 0 || (num >= super.firstdatazone && num < super.zones))
00741 return 1;
00742
00743 fprintf(stderr, "warning bad block number %ld in inode.\n", num);
00744 return 0;
00745 }
00746
00747
00748 static int was_blk_special(inode)
00749 inode_t inode;
00750 {
00751 int i, result;
00752 blockn_t block_size;
00753
00754 if (inode.size % BLOCK_SIZE || inode.ind1) return 0;
00755 block_size = inode.size / BLOCK_SIZE;
00756
00757 for (i = NR_DIRECT_ZONES - 1; i >= 0; i--)
00758 if (inode.direct[i] != 0) break;
00759
00760 result = (i < 1 && block_size > i + 1);
00761
00762 if (debug_flag && result) {
00763 fprintf(stderr, "old block special file detected (slot = %d).\n", i);
00764 }
00765 return result;
00766 }
00767
00768
00769 static void cw_inode_block(buf, ninodes, version)
00770 char *buf;
00771 inodesn_t ninodes;
00772 int version;
00773 {
00774 char output_buf[BLOCK_SIZE];
00775 char *src, *dst;
00776 inodesn_t i;
00777 int cnt, free_bytes;
00778 int *format;
00779
00780 src = buf;
00781 dst = output_buf;
00782
00783 format = (version == 1) ? inode1_format : inode2_format;
00784 for (i = 0; i < ninodes; i++) {
00785 cnt = convcpy(dst, src, format);
00786 src += cnt;
00787 dst += cnt;
00788 }
00789
00790 assert(cnt == inode_size(version));
00791
00792 free_bytes = BLOCK_SIZE - (src - buf);
00793 assert(free_bytes >= 0);
00794 if (verbose_flag && free_bytes > 0) {
00795
00796
00797
00798 fprintf(stderr, "%5d bytes (%d inodes) free in last inode block.\n",
00799 free_bytes, free_bytes / inode_size(version));
00800 memcpy(dst, src, (size_t) free_bytes);
00801 }
00802 write_block(output_buf);
00803 }
00804
00805
00806 static void proc_ind(dzmap, curr_ind, buf, super)
00807 dzmap_t dzmap;
00808 size_t curr_ind;
00809 char *buf;
00810 super_t super;
00811 {
00812 int indnum, i, ztype;
00813 int word_size;
00814
00815 unsigned char dz, tmp_dz;
00816 blockn_t blk, ind_blk;
00817 int bad_range = 0, hidden_zero = 0, zero_flag = 0, expired = 0;
00818 size_t blk_index;
00819
00820 dz = dzmap[curr_ind];
00821 indnum = dz & INDIRECT_MASK;
00822 ztype = dz & T_MASK;
00823 ind_blk = curr_ind + super.firstdatazone;
00824
00825 word_size = (super.version == 1) ? 2 : 4;
00826 assert(indnum > 0);
00827
00828 for (i = 0; i < BLOCK_SIZE; i += word_size) {
00829 if (word_size == 2)
00830 blk = two_bytes(buf + i);
00831 else
00832 blk = four_bytes(buf + i);
00833
00834 if (blk == 0)
00835 zero_flag = 1;
00836 else if (blk < super.firstdatazone || blk >= super.zones)
00837 bad_range = 1;
00838 else {
00839 if (zero_flag) hidden_zero = 1;
00840 blk_index = blk - super.firstdatazone;
00841 tmp_dz = dzmap[blk_index];
00842 if (ztype_class(tmp_dz & T_MASK) == In_use_zone) expired = 1;
00843 }
00844
00845 }
00846
00847 if (ztype_class(ztype) == In_use_zone) {
00848 if (bad_range) {
00849 fprintf(stderr, "%s zone block contains ", ind_str[indnum]);
00850 fail("illegal value");
00851 }
00852 if ((ztype == T_DIR || indnum > 1) && hidden_zero) {
00853 fprintf(stderr, "WARNING: %s zone block %ld contains ",
00854 ind_str[indnum], ind_blk);
00855 fprintf(stderr, "unexpected zero block numbers\n");
00856 }
00857 } else {
00858 if (expired) {
00859 dzmap[curr_ind] &= ~(INDIRECT_MASK & IND_CONFLICT_BIT);
00860 return;
00861 }
00862
00863
00864
00865 }
00866
00867 for (i = 0; i < BLOCK_SIZE; i += word_size) {
00868 if (word_size == 2)
00869 blk = two_bytes(buf + i);
00870 else
00871 blk = four_bytes(buf + i);
00872
00873 if (blk == 0) continue;
00874 blk_index = blk - super.firstdatazone;
00875 tmp_dz = dzmap[blk_index];
00876 if (ztype_class(tmp_dz & T_MASK) == In_use_zone) {
00877 if ((tmp_dz & INDIRECT_MASK) == indnum - 1 &&
00878 (tmp_dz & T_MASK) == ztype)
00879 fprintf(stderr, "WARNING: %s zone block %ld used more \
00880 than once\n", ind_str[indnum - 1], blk);
00881 else {
00882 fprintf(stderr, "Block %ld used more than ", blk);
00883 fail("once with different types");
00884 }
00885 }
00886 dzmap[blk_index] = (dz & ~INDIRECT_MASK) | (indnum - 1);
00887 }
00888 dzmap[curr_ind] |= IND_PROCESSED_BIT;
00889 }
00890
00891
00892 static void cw_dir_block(buf)
00893 char *buf;
00894 {
00895 char output_buf[BLOCK_SIZE];
00896 int ino, i, old_ino_offset;
00897
00898 memcpy(output_buf, buf, BLOCK_SIZE);
00899
00900 for (i = 0; i < BLOCK_SIZE; i += DIR_ENTRY_SIZE) {
00901 ino = two_bytes(buf + i);
00902 if (ino == 0) {
00903 old_ino_offset = i + DIR_ENTRY_SIZE - 2;
00904 conv2cpy(output_buf + old_ino_offset, buf + old_ino_offset);
00905 } else
00906 conv2cpy(output_buf + i, buf + i);
00907 }
00908 write_block(output_buf);
00909 }
00910
00911
00912 static void dzmap_add_inode(dzmap, inode, super)
00913 dzmap_t dzmap;
00914 inode_t inode;
00915 super_t super;
00916 {
00917 int i;
00918
00919 if (inode.size == 0 || !check_inode(inode, super)) return;
00920
00921 for (i = 0; i < NR_DIRECT_ZONES; i++)
00922 dz_update(dzmap, inode.direct[i], 0, inode.ztype, super);
00923
00924 dz_update(dzmap, inode.ind1, 1, inode.ztype, super);
00925 dz_update(dzmap, inode.ind2, 2, inode.ztype, super);
00926 dz_update(dzmap, inode.ind3, 3, inode.ztype, super);
00927 }
00928
00929
00930 static void dz_update(dzmap, blknum, new_indnum, new_ztype, super)
00931 dzmap_t dzmap;
00932 blockn_t blknum;
00933 int new_indnum;
00934 int new_ztype;
00935 super_t super;
00936 {
00937 size_t dznum;
00938 int old_indnum;
00939 int old_ztype;
00940 unsigned char *dz;
00941 char new_dz;
00942
00943
00944 if (blknum == 0) return;
00945
00946 dznum = (size_t) (blknum - super.firstdatazone);
00947
00948 dz = &dzmap[dznum];
00949 old_indnum = *dz & INDIRECT_MASK;
00950 old_ztype = *dz & T_MASK;
00951
00952 new_dz = new_ztype | new_indnum;
00953
00954 if (ztype_class(new_ztype) > ztype_class(old_ztype)) {
00955 *dz = new_dz;
00956 return;
00957 } else if (ztype_class(new_ztype) < ztype_class(old_ztype))
00958 return;
00959
00960
00961
00962 if (ztype_class(old_ztype) == In_use_zone) {
00963 if (new_indnum == old_indnum && new_ztype == old_ztype) {
00964 fprintf(stderr, "WARNING: file system corrupt, zone block %ld \
00965 is used more than once.\n", blknum);
00966 return;
00967 }
00968 fprintf(stderr, "ERROR: file system corrupt, zone block %ld is used \
00969 more than once.\n", blknum);
00970 fail("Can't determine its type");
00971 }
00972 assert(ztype_class(old_ztype) == Old_zone);
00973
00974
00975 if (new_indnum != old_indnum) {
00976 *dz |= IND_CONFLICT_BIT;
00977 if (new_indnum > old_indnum) {
00978 *dz &= ~INDIRECT_MASK;
00979 *dz |= new_indnum;
00980 }
00981 }
00982 if (new_ztype == T_MAYBE_OLD_DIR || old_ztype == T_MAYBE_OLD_DIR) {
00983 *dz |= TYPE_CONFLICT_BIT;
00984 *dz &= ~T_MASK;
00985 *dz |= T_MAYBE_OLD_DIR;
00986 }
00987 }
00988
00989
00990 static class_t ztype_class(ztype)
00991 int ztype;
00992 {
00993 class_t class;
00994
00995 if (ztype == T_MAYBE_OLD_DIR || ztype == T_OLD_NON_DIR)
00996 class = Old_zone;
00997 else if (ztype == T_DIR || ztype == T_NON_DIR)
00998 class = In_use_zone;
00999 else
01000 class = Unused_zone;
01001
01002 return class;
01003 }
01004
01005
01006 static void fail(str)
01007 char *str;
01008 {
01009 fprintf(stderr, "%s\n", str);
01010 exit(1);
01011 }
01012
01013
01014 static unsigned int two_bytes(buf)
01015 char buf[2];
01016 {
01017 unsigned char *ubuf = (unsigned char *) buf;
01018
01019 if (big_endian_fs)
01020 return(ubuf[0] << 8) | ubuf[1];
01021 else
01022 return(ubuf[1] << 8) | ubuf[0];
01023 }
01024
01025
01026 static long four_bytes(buf)
01027 char buf[4];
01028 {
01029 unsigned char *ubuf = (unsigned char *) buf;
01030 register int r1, r2;
01031
01032 if (big_endian_fs) {
01033 r1 = (ubuf[0] << 8) | ubuf[1];
01034 r2 = (ubuf[2] << 8) | ubuf[3];
01035 } else {
01036 r2 = (ubuf[1] << 8) | ubuf[0];
01037 r1 = (ubuf[3] << 8) | ubuf[2];
01038 }
01039 return((long) r1 << 16) | r2;
01040 }
01041
01042
01043 static void usage(arg0)
01044 char *arg0;
01045 {
01046 fprintf(stderr, "usage: %s [-v] srcfs [destfs]\n", arg0);
01047 exit(2);
01048 }