1 /* mkfs - make the MINIX filesystem Authors: Tanenbaum et al. */
3 /* Authors: Andy Tanenbaum, Paul Ogilvie, Frans Meulenbroeks, Bruce Evans
5 * This program can make version 1, 2 and 3 file systems, as follows:
6 * mkfs /dev/fd0 1200 # Version 3 (default)
7 * mkfs -1 /dev/fd0 360 # Version 1
9 * Note that the version 1 and 2 file systems produced by this program are not
10 * compatible with the original version 1 and 2 file system layout.
13 #include <sys/types.h>
24 #include <minix/config.h>
25 #include <minix/const.h>
26 #include <minix/type.h>
27 #include <minix/minlib.h>
28 #include "../../servers/mfs/const.h"
29 #if (MACHINE == IBM_PC)
30 #include <minix/partition.h>
31 #include <minix/u64.h>
32 #include <sys/ioctl.h>
39 #define EXTERN /* get rid of EXTERN by making it null */
40 #include "../../servers/mfs/super.h"
41 #include "../../servers/mfs/type.h"
42 #include "../../servers/mfs/inode.h"
43 #include <minix/fslib.h>
46 #define max(a,b) ((a) > (b) ? (a) : (b))
60 #define BIT_MAP_SHIFT 13
61 #define INODE_MAX ((unsigned) 65535)
65 maybedefine O_RDONLY
4 /* O_RDONLY | BINARY_BIT */
66 maybedefine BWRITE
5 /* O_WRONLY | BINARY_BIT */
69 #if (MACHINE == ATARI)
76 int next_zone
, next_inode
, zone_size
, zone_shift
= 0, zoff
;
78 int inode_offset
, lct
= 0, disk
, fd
, print
= 0, file
= 0;
79 unsigned int nrinodes
;
80 int override
= 0, simple
= 0, dflag
;
81 int donttest
; /* skip test if it fits on medium */
84 long current_time
, bin_time
;
86 char *umap_array
; /* bit map tells if block read yet */
87 int umap_array_elements
= 0;
88 block_t zone_map
; /* where is zone map? (depends on # inodes) */
91 unsigned int block_size
;
95 _PROTOTYPE(int main
, (int argc
, char **argv
));
96 _PROTOTYPE(block_t sizeup
, (char *device
));
97 _PROTOTYPE(void super
, (zone_t zones
, Ino_t inodes
));
98 _PROTOTYPE(void rootdir
, (Ino_t inode
));
99 _PROTOTYPE(void eat_dir
, (Ino_t parent
));
100 _PROTOTYPE(void eat_file
, (Ino_t inode
, int f
));
101 _PROTOTYPE(void enter_dir
, (Ino_t parent
, char *name
, Ino_t child
));
102 _PROTOTYPE(void incr_size
, (Ino_t n
, long count
));
103 _PROTOTYPE(PRIVATE ino_t alloc_inode
, (int mode
, int usrid
, int grpid
));
104 _PROTOTYPE(PRIVATE zone_t alloc_zone
, (void));
105 _PROTOTYPE(void add_zone
, (Ino_t n
, zone_t z
, long bytes
, long cur_time
));
106 _PROTOTYPE(void add_z_1
, (Ino_t n
, zone_t z
, long bytes
, long cur_time
));
107 _PROTOTYPE(void add_z_2
, (Ino_t n
, zone_t z
, long bytes
, long cur_time
));
108 _PROTOTYPE(void incr_link
, (Ino_t n
));
109 _PROTOTYPE(void insert_bit
, (block_t block
, int bit
));
110 _PROTOTYPE(int mode_con
, (char *p
));
111 _PROTOTYPE(void getline
, (char line
[LINE_LEN
], char *parse
[MAX_TOKENS
]));
112 _PROTOTYPE(void check_mtab
, (char *devname
));
113 _PROTOTYPE(long file_time
, (int f
));
114 _PROTOTYPE(void pexit
, (char *s
));
115 _PROTOTYPE(void copy
, (char *from
, char *to
, int count
));
116 _PROTOTYPE(void print_fs
, (void));
117 _PROTOTYPE(int read_and_set
, (block_t n
));
118 _PROTOTYPE(void special
, (char *string
));
119 _PROTOTYPE(void get_block
, (block_t n
, char *buf
));
120 _PROTOTYPE(void get_super_block
, (char *buf
));
121 _PROTOTYPE(void put_block
, (block_t n
, char *buf
));
122 _PROTOTYPE(void cache_init
, (void));
123 _PROTOTYPE(void flush
, (void));
124 _PROTOTYPE(void mx_read
, (int blocknr
, char *buf
));
125 _PROTOTYPE(void mx_write
, (int blocknr
, char *buf
));
126 _PROTOTYPE(void dexit
, (char *s
, int sectnum
, int err
));
127 _PROTOTYPE(void usage
, (void));
128 _PROTOTYPE(char *alloc_block
, (void));
130 /*================================================================
131 * mkfs - make filesystem
132 *===============================================================*/
137 int nread
, mode
, usrid
, grpid
, ch
;
138 block_t blocks
, maxblocks
;
143 char *token
[MAX_TOKENS
], line
[LINE_LEN
];
146 /* Get two times, the current time and the mod time of the binary of
147 * mkfs itself. When the -d flag is used, the later time is put into
148 * the i_mtimes of all the files. This feature is useful when
149 * producing a set of file systems, and one wants all the times to be
150 * identical. First you set the time of the mkfs binary to what you
153 current_time
= time((time_t *) 0); /* time mkfs is being run */
154 stat(argv
[0], &statbuf
);
155 bin_time
= statbuf
.st_mtime
; /* time when mkfs binary was last modified */
157 /* Process switches. */
162 inodes_per_block
= 0;
164 while ((ch
= getopt(argc
, argv
, "12b:di:lotB:")) != EOF
)
168 inodes_per_block
= V1_INODES_PER_BLOCK
;
174 blocks
= strtoul(optarg
, (char **) NULL
, 0);
178 current_time
= bin_time
;
181 i
= strtoul(optarg
, (char **) NULL
, 0);
183 case 'l': print
= 1; break;
184 case 'o': override
= 1; break;
185 case 't': donttest
= 1; break;
186 case 'B': block_size
= atoi(optarg
); break;
190 if (argc
== optind
) usage();
192 if(fs_version
== 3) {
193 if(!block_size
) block_size
= _MAX_BLOCK_SIZE
; /* V3 default block size */
194 if(block_size
%SECTOR_SIZE
|| block_size
< _MIN_BLOCK_SIZE
) {
195 fprintf(stderr
, "block size must be multiple of sector (%d) "
196 "and at least %d bytes\n",
197 SECTOR_SIZE
, _MIN_BLOCK_SIZE
);
198 pexit("specified block size illegal");
200 if(block_size
%V2_INODE_SIZE
) {
201 fprintf(stderr
, "block size must be a multiple of inode size (%d bytes)\n",
203 pexit("specified block size illegal");
207 pexit("Can't specify a block size if FS version is <3");
209 block_size
= _STATIC_BLOCK_SIZE
; /* V1/V2 block size */
212 if(!inodes_per_block
)
213 inodes_per_block
= V2_INODES_PER_BLOCK(block_size
);
215 /* now that the block size is known, do buffer allocations where
218 zero
= alloc_block();
219 bzero(zero
, block_size
);
221 /* Determine the size of the device if not specified as -b or proto. */
222 maxblocks
= sizeup(argv
[optind
]);
223 if (argc
- optind
== 1 && blocks
== 0) {
225 /* blocks == 0 is checked later, but leads to a funny way of
226 * reporting a 0-sized device (displays usage).
229 fprintf(stderr
, "%s: zero size device.\n", progname
);
234 /* The remaining args must be 'special proto', or just 'special' if the
235 * no. of blocks has already been specified.
237 if (argc
- optind
!= 2 && (argc
- optind
!= 1 || blocks
== 0)) usage();
239 if (blocks
> maxblocks
) {
240 fprintf(stderr
, "%s: %s: number of blocks too large for device.\n",
241 progname
, argv
[optind
]);
246 check_mtab(argv
[optind
]);
248 /* Check and start processing proto. */
249 optarg
= argv
[++optind
];
250 if (optind
< argc
&& (proto
= fopen(optarg
, "r")) != NULL
) {
251 /* Prototype file is readable. */
253 getline(line
, token
); /* skip boot block info */
255 /* Read the line with the block and inode counts. */
256 getline(line
, token
);
257 blocks
= atol(token
[0]);
258 inodes
= atoi(token
[1]);
260 /* Process mode line for root directory. */
261 getline(line
, token
);
262 mode
= mode_con(token
[0]);
263 usrid
= atoi(token
[1]);
264 grpid
= atoi(token
[2]);
268 /* Maybe the prototype file is just a size. Check. */
269 blocks
= strtoul(optarg
, (char **) NULL
, 0);
270 if (blocks
== 0) pexit("Can't open prototype file");
273 u32_t kb
= div64u(mul64u(blocks
, block_size
), 1024);
275 if (kb
>= 100000) i
= kb
/ 4;
277 /* round up to fill inode block */
278 i
+= inodes_per_block
- 1;
279 i
= i
/ inodes_per_block
* inodes_per_block
;
280 if (i
> INODE_MAX
&& fs_version
< 3) i
= INODE_MAX
;
283 if (blocks
< 5) pexit("Block count too small");
284 if (i
< 1) pexit("Inode count too small");
285 if (i
> INODE_MAX
&& fs_version
< 3) pexit("Inode count too large");
288 /* Make simple file system of the given size, using defaults. */
300 bytes
= 1 + blocks
/8;
301 if(!(umap_array
= malloc(bytes
))) {
302 fprintf(stderr
, "mkfs: can't allocate block bitmap (%d bytes).\n",
306 umap_array_elements
= bytes
;
310 special(argv
[--optind
]);
317 testb
= (short *) alloc_block();
319 /* Try writing the last block of partition or diskette. */
320 if(lseek64(fd
, mul64u(blocks
- 1, block_size
), SEEK_SET
, NULL
) < 0) {
321 pexit("couldn't seek to last block to test size (1)");
325 testb
[block_size
/2-1] = 0x1F2F;
326 if ((w
=write(fd
, (char *) testb
, block_size
)) != block_size
) {
327 if(w
< 0) perror("write");
328 printf("%d/%d\n", w
, block_size
);
329 pexit("File system is too big for minor device (write)");
331 sync(); /* flush write, so if error next read fails */
332 if(lseek64(fd
, mul64u(blocks
- 1, block_size
), SEEK_SET
, NULL
) < 0) {
333 pexit("couldn't seek to last block to test size (2)");
337 nread
= read(fd
, (char *) testb
, block_size
);
338 if (nread
!= block_size
|| testb
[0] != 0x3245 || testb
[1] != 0x11FF ||
339 testb
[block_size
/2-1] != 0x1F2F) {
340 if(nread
< 0) perror("read");
341 printf("nread = %d\n", nread
);
342 printf("testb = 0x%x 0x%x 0x%x\n", testb
[0], testb
[1], testb
[block_size
-1]);
343 pexit("File system is too big for minor device (read)");
345 lseek64(fd
, mul64u(blocks
- 1, block_size
), SEEK_SET
, NULL
);
348 if (write(fd
, (char *) testb
, block_size
) != block_size
)
349 pexit("File system is too big for minor device (write2)");
350 lseek(fd
, 0L, SEEK_SET
);
355 /* Make the file-system */
359 put_block((block_t
) 0, zero
); /* Write a null boot block. */
361 zone_shift
= 0; /* for future use */
362 zones
= nrblocks
>> zone_shift
;
364 super(zones
, inodes
);
366 root_inum
= alloc_inode(mode
, usrid
, grpid
);
368 if (simple
== 0) eat_dir(root_inum
);
370 if (print
) print_fs();
378 /*================================================================
379 * sizeup - determine device size
380 *===============================================================*/
381 block_t
sizeup(device
)
385 struct partition entry
;
391 if ((fd
= open(device
, O_RDONLY
)) == -1) {
393 perror("sizeup open");
396 if (ioctl(fd
, DIOCGETP
, &entry
) == -1) {
397 perror("sizeup ioctl");
398 if(fstat(fd
, &st
) < 0) {
400 entry
.size
= cvu64(0);
402 fprintf(stderr
, "used fstat instead\n");
403 entry
.size
= cvu64(st
.st_size
);
407 d
= div64u(entry
.size
, block_size
);
408 rem
= rem64u(entry
.size
, block_size
);
410 resize
= add64u(mul64u(d
, block_size
), rem
);
411 if(cmp64(resize
, entry
.size
) != 0) {
413 fprintf(stderr
, "mkfs: truncating FS at %lu blocks\n", d
);
420 /*================================================================
421 * super - construct a superblock
422 *===============================================================*/
424 void super(zones
, inodes
)
434 struct super_block
*sup
;
439 for (cp
= buf
; cp
< &buf
[block_size
]; cp
++) *cp
= 0;
440 sup
= (struct super_block
*) buf
; /* lint - might use a union */
442 sup
->s_ninodes
= inodes
;
443 if (fs_version
== 1) {
444 sup
->s_nzones
= zones
;
445 if (sup
->s_nzones
!= zones
) pexit("too many zones");
447 sup
->s_nzones
= 0; /* not used in V2 - 0 forces errors early */
448 sup
->s_zones
= zones
;
451 #define BIGGERBLOCKS "Please try a larger block size for an FS of this size.\n"
452 sup
->s_imap_blocks
= nb
= bitmapsize((bit_t
) (1 + inodes
), block_size
);
453 if(sup
->s_imap_blocks
!= nb
) {
454 fprintf(stderr
, "mkfs: too many inode bitmap blocks.\n" BIGGERBLOCKS
);
457 sup
->s_zmap_blocks
= nb
= bitmapsize((bit_t
) zones
, block_size
);
458 if(nb
!= sup
->s_zmap_blocks
) {
459 fprintf(stderr
, "mkfs: too many block bitmap blocks.\n" BIGGERBLOCKS
);
462 inode_offset
= START_BLOCK
+ sup
->s_imap_blocks
+ sup
->s_zmap_blocks
;
463 inodeblks
= (inodes
+ inodes_per_block
- 1) / inodes_per_block
;
464 initblks
= inode_offset
+ inodeblks
;
465 sup
->s_firstdatazone_old
= nb
=
466 (initblks
+ (1 << zone_shift
) - 1) >> zone_shift
;
467 if(nb
>= zones
) pexit("bit maps too large");
468 if(nb
!= sup
->s_firstdatazone_old
) {
469 /* The field is too small to store the value. Fortunately, the value
470 * can be computed from other fields. We set the on-disk field to zero
471 * to indicate that it must not be used. Eventually, we can always set
472 * the on-disk field to zero, and stop using it.
474 sup
->s_firstdatazone_old
= 0;
476 sup
->s_firstdatazone
= nb
;
477 zoff
= sup
->s_firstdatazone
- 1;
478 sup
->s_log_zone_size
= zone_shift
;
479 if (fs_version
== 1) {
480 sup
->s_magic
= SUPER_MAGIC
; /* identify super blocks */
481 v1sq
= (zone_t
) V1_INDIRECTS
* V1_INDIRECTS
;
482 zo
= V1_NR_DZONES
+ (long) V1_INDIRECTS
+ v1sq
;
483 sup
->s_max_size
= zo
* block_size
;
485 v2sq
= (zone_t
) V2_INDIRECTS(block_size
) * V2_INDIRECTS(block_size
);
486 zo
= V2_NR_DZONES
+ (zone_t
) V2_INDIRECTS(block_size
) + v2sq
;
487 if(fs_version
== 2) {
488 sup
->s_magic
= SUPER_V2
;/* identify super blocks */
489 sup
->s_max_size
= zo
* block_size
;
491 sup
->s_magic
= SUPER_V3
;
492 sup
->s_block_size
= block_size
;
493 sup
->s_disk_version
= 0;
494 #define MAX_MAX_SIZE ((unsigned long) LONG_MAX)
495 if(MAX_MAX_SIZE
/block_size
< zo
) {
496 sup
->s_max_size
= MAX_MAX_SIZE
;
499 sup
->s_max_size
= zo
* block_size
;
504 zone_size
= 1 << zone_shift
; /* nr of blocks per zone */
506 if (lseek(fd
, (off_t
) _STATIC_BLOCK_SIZE
, SEEK_SET
) == (off_t
) -1) {
507 pexit("super() couldn't seek");
509 if (write(fd
, buf
, _STATIC_BLOCK_SIZE
) != _STATIC_BLOCK_SIZE
) {
510 pexit("super() couldn't write");
513 /* Clear maps and inodes. */
514 for (i
= START_BLOCK
; i
< initblks
; i
++) put_block((block_t
) i
, zero
);
516 next_zone
= sup
->s_firstdatazone
;
519 zone_map
= INODE_MAP
+ sup
->s_imap_blocks
;
521 insert_bit(zone_map
, 0); /* bit zero must always be allocated */
522 insert_bit((block_t
) INODE_MAP
, 0); /* inode zero not used but
523 * must be allocated */
529 /*================================================================
530 * rootdir - install the root directory
531 *===============================================================*/
538 add_zone(inode
, z
, 2 * sizeof(struct direct
), current_time
);
539 enter_dir(inode
, ".", inode
);
540 enter_dir(inode
, "..", inode
);
546 /*================================================================
547 * eat_dir - recursively install directory
548 *===============================================================*/
552 /* Read prototype lines and set up directory. Recurse if need be. */
553 char *token
[MAX_TOKENS
], *p
;
555 int mode
, usrid
, grpid
, maj
, min
, f
;
561 getline(line
, token
);
563 if (*p
== '$') return;
566 usrid
= atoi(token
[2]);
567 grpid
= atoi(token
[3]);
568 if (grpid
& 0200) fprintf(stderr
, "A.S.Tanenbaum\n");
569 n
= alloc_inode(mode
, usrid
, grpid
);
571 /* Enter name in directory and update directory's size. */
572 enter_dir(parent
, token
[0], n
);
573 incr_size(parent
, sizeof(struct direct
));
575 /* Check to see if file is directory or special. */
578 /* This is a directory. */
579 z
= alloc_zone(); /* zone for new directory */
580 add_zone(n
, z
, 2 * sizeof(struct direct
), current_time
);
581 enter_dir(n
, ".", n
);
582 enter_dir(n
, "..", parent
);
586 } else if (*p
== 'b' || *p
== 'c') {
588 maj
= atoi(token
[4]);
589 min
= atoi(token
[5]);
591 if (token
[6]) size
= atoi(token
[6]);
592 size
= block_size
* size
;
593 add_zone(n
, (zone_t
) ((maj
<< 8) | min
), size
, current_time
);
595 /* Regular file. Go read it. */
596 if ((f
= open(token
[4], O_RDONLY
)) < 0) {
597 fprintf(stderr
, "%s: Can't open %s: %s\n",
598 progname
, token
[4], strerror(errno
));
607 /*================================================================
608 * eat_file - copy file to MINIX
609 *===============================================================*/
610 /* Zonesize >= blocksize */
611 void eat_file(inode
, f
)
623 for (i
= 0, j
= 0; i
< zone_size
; i
++, j
+= ct
) {
624 for (k
= 0; k
< block_size
; k
++) buf
[k
] = 0;
625 if ((ct
= read(f
, buf
, block_size
)) > 0) {
626 if (i
== 0) z
= alloc_zone();
627 put_block((z
<< zone_shift
) + i
, buf
);
630 timeval
= (dflag
? current_time
: file_time(f
));
631 if (ct
) add_zone(inode
, z
, (long) j
, timeval
);
632 } while (ct
== block_size
);
638 /*================================================================
639 * directory & inode management assist group
640 *===============================================================*/
641 void enter_dir(parent
, name
, child
)
645 /* Enter child in parent directory */
646 /* Works for dir > 1 block and zone > block */
651 struct direct
*dir_entry
;
652 d1_inode ino1
[V1_INODES_PER_BLOCK
];
656 b
= ((parent
- 1) / inodes_per_block
) + inode_offset
;
657 off
= (parent
- 1) % inodes_per_block
;
659 if(!(dir_entry
= malloc(NR_DIR_ENTRIES(block_size
) * sizeof(*dir_entry
))))
660 pexit("couldn't allocate directory entry");
662 if(!(ino2
= malloc(V2_INODES_PER_BLOCK(block_size
) * sizeof(*ino2
))))
663 pexit("couldn't allocate block of inodes entry");
665 if (fs_version
== 1) {
666 get_block(b
, (char *) ino1
);
667 nr_dzones
= V1_NR_DZONES
;
669 get_block(b
, (char *) ino2
);
670 nr_dzones
= V2_NR_DZONES
;
672 for (k
= 0; k
< nr_dzones
; k
++) {
673 if (fs_version
== 1) {
674 z
= ino1
[off
].d1_zone
[k
];
677 ino1
[off
].d1_zone
[k
] = z
;
680 z
= ino2
[off
].d2_zone
[k
];
683 ino2
[off
].d2_zone
[k
] = z
;
686 for (l
= 0; l
< zone_size
; l
++) {
687 get_block((z
<< zone_shift
) + l
, (char *) dir_entry
);
688 for (i
= 0; i
< NR_DIR_ENTRIES(block_size
); i
++) {
689 if (dir_entry
[i
].d_ino
== 0) {
690 dir_entry
[i
].d_ino
= child
;
692 p2
= dir_entry
[i
].d_name
;
693 j
= sizeof(dir_entry
[i
].d_name
);
698 put_block((z
<< zone_shift
) + l
, (char *) dir_entry
);
699 if (fs_version
== 1) {
700 put_block(b
, (char *) ino1
);
702 put_block(b
, (char *) ino2
);
712 printf("Directory-inode %d beyond direct blocks. Could not enter %s\n",
718 void add_zone(n
, z
, bytes
, cur_time
)
721 long bytes
, cur_time
;
723 if (fs_version
== 1) {
724 add_z_1(n
, z
, bytes
, cur_time
);
726 add_z_2(n
, z
, bytes
, cur_time
);
730 void add_z_1(n
, z
, bytes
, cur_time
)
733 long bytes
, cur_time
;
735 /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
740 zone1_t blk
[V1_INDIRECTS
];
742 d1_inode inode
[V1_INODES_PER_BLOCK
];
744 b
= ((n
- 1) / V1_INODES_PER_BLOCK
) + inode_offset
;
745 off
= (n
- 1) % V1_INODES_PER_BLOCK
;
746 get_block(b
, (char *) inode
);
749 p
->d1_mtime
= cur_time
;
750 for (i
= 0; i
< V1_NR_DZONES
; i
++)
751 if (p
->d1_zone
[i
] == 0) {
752 p
->d1_zone
[i
] = (zone1_t
) z
;
753 put_block(b
, (char *) inode
);
756 put_block(b
, (char *) inode
);
758 /* File has grown beyond a small file. */
759 if (p
->d1_zone
[V1_NR_DZONES
] == 0)
760 p
->d1_zone
[V1_NR_DZONES
] = (zone1_t
) alloc_zone();
761 indir
= p
->d1_zone
[V1_NR_DZONES
];
762 put_block(b
, (char *) inode
);
763 b
= indir
<< zone_shift
;
764 get_block(b
, (char *) blk
);
765 for (i
= 0; i
< V1_INDIRECTS
; i
++)
767 blk
[i
] = (zone1_t
) z
;
768 put_block(b
, (char *) blk
);
771 pexit("File has grown beyond single indirect");
774 void add_z_2(n
, z
, bytes
, cur_time
)
777 long bytes
, cur_time
;
779 /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
788 if(!(blk
= malloc(V2_INDIRECTS(block_size
)*sizeof(*blk
))))
789 pexit("Couldn't allocate indirect block");
791 if(!(inode
= malloc(V2_INODES_PER_BLOCK(block_size
)*sizeof(*inode
))))
792 pexit("Couldn't allocate block of inodes");
794 b
= ((n
- 1) / V2_INODES_PER_BLOCK(block_size
)) + inode_offset
;
795 off
= (n
- 1) % V2_INODES_PER_BLOCK(block_size
);
796 get_block(b
, (char *) inode
);
799 p
->d2_mtime
= cur_time
;
800 for (i
= 0; i
< V2_NR_DZONES
; i
++)
801 if (p
->d2_zone
[i
] == 0) {
803 put_block(b
, (char *) inode
);
808 put_block(b
, (char *) inode
);
810 /* File has grown beyond a small file. */
811 if (p
->d2_zone
[V2_NR_DZONES
] == 0) p
->d2_zone
[V2_NR_DZONES
] = alloc_zone();
812 indir
= p
->d2_zone
[V2_NR_DZONES
];
813 put_block(b
, (char *) inode
);
814 b
= indir
<< zone_shift
;
815 get_block(b
, (char *) blk
);
816 for (i
= 0; i
< V2_INDIRECTS(block_size
); i
++)
819 put_block(b
, (char *) blk
);
824 pexit("File has grown beyond single indirect");
831 /* Increment the link count to inode n */
833 static int enter
= 0;
838 b
= ((n
- 1) / inodes_per_block
) + inode_offset
;
839 off
= (n
- 1) % inodes_per_block
;
840 if (fs_version
== 1) {
841 d1_inode inode1
[V1_INODES_PER_BLOCK
];
843 get_block(b
, (char *) inode1
);
844 inode1
[off
].d1_nlinks
++;
845 put_block(b
, (char *) inode1
);
847 static d2_inode
*inode2
= NULL
;
850 n
= sizeof(*inode2
) * V2_INODES_PER_BLOCK(block_size
);
851 if(!inode2
&& !(inode2
= malloc(n
)))
852 pexit("couldn't allocate a block of inodes");
854 get_block(b
, (char *) inode2
);
855 inode2
[off
].d2_nlinks
++;
856 put_block(b
, (char *) inode2
);
862 void incr_size(n
, count
)
866 /* Increment the file-size in inode n */
870 b
= ((n
- 1) / inodes_per_block
) + inode_offset
;
871 off
= (n
- 1) % inodes_per_block
;
872 if (fs_version
== 1) {
873 d1_inode inode1
[V1_INODES_PER_BLOCK
];
875 get_block(b
, (char *) inode1
);
876 inode1
[off
].d1_size
+= count
;
877 put_block(b
, (char *) inode1
);
880 if(!(inode2
= malloc(V2_INODES_PER_BLOCK(block_size
) * sizeof(*inode2
))))
881 pexit("couldn't allocate a block of inodes");
883 get_block(b
, (char *) inode2
);
884 inode2
[off
].d2_size
+= count
;
885 put_block(b
, (char *) inode2
);
891 /*================================================================
892 * allocation assist group
893 *===============================================================*/
894 PRIVATE ino_t
alloc_inode(mode
, usrid
, grpid
)
895 int mode
, usrid
, grpid
;
902 if (num
> nrinodes
) {
903 fprintf(stderr
, "have %d inodoes\n", nrinodes
);
904 pexit("File system does not have enough inodes");
906 b
= ((num
- 1) / inodes_per_block
) + inode_offset
;
907 off
= (num
- 1) % inodes_per_block
;
908 if (fs_version
== 1) {
909 d1_inode inode1
[V1_INODES_PER_BLOCK
];
911 get_block(b
, (char *) inode1
);
912 inode1
[off
].d1_mode
= mode
;
913 inode1
[off
].d1_uid
= usrid
;
914 inode1
[off
].d1_gid
= grpid
;
915 put_block(b
, (char *) inode1
);
919 if(!(inode2
= malloc(V2_INODES_PER_BLOCK(block_size
) * sizeof(*inode2
))))
920 pexit("couldn't allocate a block of inodes");
922 get_block(b
, (char *) inode2
);
923 inode2
[off
].d2_mode
= mode
;
924 inode2
[off
].d2_uid
= usrid
;
925 inode2
[off
].d2_gid
= grpid
;
926 put_block(b
, (char *) inode2
);
931 /* Set the bit in the bit map. */
932 /* DEBUG FIXME. This assumes the bit is in the first inode map block. */
933 insert_bit((block_t
) INODE_MAP
, (int) num
);
938 PRIVATE zone_t
alloc_zone()
940 /* Allocate a new zone */
941 /* Works for zone > block */
948 if ((b
+ zone_size
) > nrblocks
)
949 pexit("File system not big enough for all the files");
950 for (i
= 0; i
< zone_size
; i
++)
951 put_block(b
+ i
, zero
); /* give an empty zone */
952 /* DEBUG FIXME. This assumes the bit is in the first zone map block. */
953 insert_bit(zone_map
, (int) (z
- zoff
)); /* lint, NOT OK because
954 * z hasn't been broken
961 void insert_bit(block
, bit
)
965 /* Insert 'count' bits in the bitmap */
969 buf
= (short *) alloc_block();
971 if (block
< 0) pexit("insert_bit called with negative argument");
972 get_block(block
, (char *) buf
);
973 w
= bit
/ (8 * sizeof(short));
974 s
= bit
% (8 * sizeof(short));
976 put_block(block
, (char *) buf
);
982 /*================================================================
983 * proto-file processing assist group
984 *===============================================================*/
988 /* Convert string to mode */
989 int o1
, o2
, o3
, mode
;
998 mode
= (o1
<< 6) | (o2
<< 3) | o3
;
999 if (c1
== 'd') mode
+= I_DIRECTORY
;
1000 if (c1
== 'b') mode
+= I_BLOCK_SPECIAL
;
1001 if (c1
== 'c') mode
+= I_CHAR_SPECIAL
;
1002 if (c1
== '-') mode
+= I_REGULAR
;
1003 if (c2
== 'u') mode
+= I_SET_UID_BIT
;
1004 if (c3
== 'g') mode
+= I_SET_GID_BIT
;
1008 void getline(line
, parse
)
1009 char *parse
[MAX_TOKENS
];
1010 char line
[LINE_LEN
];
1012 /* Read a line and break it up in tokens */
1017 for (k
= 0; k
< MAX_TOKENS
; k
++) parse
[k
] = 0;
1018 for (k
= 0; k
< LINE_LEN
; k
++) line
[k
] = 0;
1023 if (++k
> LINE_LEN
) pexit("Line too long");
1025 if (d
== EOF
) pexit("Unexpected end-of-file");
1027 if (*p
== '\n') lct
++;
1028 if (*p
== ' ' || *p
== '\t') *p
= 0;
1042 if (c
== '\n') return;
1043 if (c
== 0) continue;
1047 } while (c
!= 0 && c
!= '\n');
1052 /*================================================================
1054 *===============================================================*/
1055 void check_mtab(devname
)
1056 char *devname
; /* /dev/hd1 or whatever */
1058 /* Check to see if the special file named in s is mounted. */
1062 char special
[PATH_MAX
+ 1], mounted_on
[PATH_MAX
+ 1], version
[10], rw_flag
[10];
1064 r
= stat(devname
, &sb
);
1067 if (errno
== ENOENT
)
1068 return; /* Does not exist, and therefore not mounted. */
1069 fprintf(stderr
, "%s: stat %s failed: %s\n",
1070 progname
, devname
, strerror(errno
));
1073 if (!S_ISBLK(sb
.st_mode
))
1075 /* Not a block device and therefore not mounted. */
1079 if (load_mtab("mkfs") < 0) return;
1081 n
= get_mtab_entry(special
, mounted_on
, version
, rw_flag
);
1083 if (strcmp(devname
, special
) == 0) {
1084 /* Can't mkfs on top of a mounted file system. */
1085 fprintf(stderr
, "%s: %s is mounted on %s\n",
1086 progname
, devname
, mounted_on
);
1097 struct stat statbuf
;
1099 return(statbuf
.st_mtime
);
1100 #else /* fstat not supported by DOS */
1109 fprintf(stderr
, "%s: %s\n", progname
, s
);
1111 fprintf(stderr
, "Line %d being processed when error detected.\n", lct
);
1117 void copy(from
, to
, count
)
1121 while (count
--) *to
++ = *from
++;
1128 if(!(buf
= malloc(block_size
))) {
1129 pexit("couldn't allocate filesystem buffer");
1131 bzero(buf
, block_size
);
1140 d1_inode inode1
[V1_INODES_PER_BLOCK
];
1142 unsigned short *usbuf
;
1143 block_t b
, inode_limit
;
1146 if(!(inode2
= malloc(V2_INODES_PER_BLOCK(block_size
) * sizeof(*inode2
))))
1147 pexit("couldn't allocate a block of inodes");
1149 if(!(dir
= malloc(NR_DIR_ENTRIES(block_size
)*sizeof(*dir
))))
1150 pexit("malloc of directory entry failed");
1152 usbuf
= (unsigned short *) alloc_block();
1154 get_super_block((char *) usbuf
);
1155 printf("\nSuperblock: ");
1156 for (i
= 0; i
< 8; i
++) printf("%06o ", usbuf
[i
]);
1157 get_block((block_t
) 2, (char *) usbuf
);
1158 printf("...\nInode map: ");
1159 for (i
= 0; i
< 9; i
++) printf("%06o ", usbuf
[i
]);
1160 get_block((block_t
) 3, (char *) usbuf
);
1161 printf("...\nZone map: ");
1162 for (i
= 0; i
< 9; i
++) printf("%06o ", usbuf
[i
]);
1169 for (b
= inode_offset
; k
< nrinodes
; b
++) {
1170 if (fs_version
== 1) {
1171 get_block(b
, (char *) inode1
);
1173 get_block(b
, (char *) inode2
);
1175 for (i
= 0; i
< inodes_per_block
; i
++) {
1176 k
= inodes_per_block
* (int) (b
- inode_offset
) + i
+ 1;
1178 if (k
> nrinodes
) break;
1179 if (fs_version
== 1) {
1180 if (inode1
[i
].d1_mode
!= 0) {
1181 printf("Inode %2d: mode=", k
);
1182 printf("%06o", inode1
[i
].d1_mode
);
1183 printf(" uid=%2d gid=%2d size=",
1184 inode1
[i
].d1_uid
, inode1
[i
].d1_gid
);
1185 printf("%6ld", inode1
[i
].d1_size
);
1186 printf(" zone[0]=%d\n", inode1
[i
].d1_zone
[0]);
1188 if ((inode1
[i
].d1_mode
& I_TYPE
) == I_DIRECTORY
) {
1189 /* This is a directory */
1190 get_block(inode1
[i
].d1_zone
[0], (char *) dir
);
1191 for (j
= 0; j
< NR_DIR_ENTRIES(block_size
); j
++)
1193 printf("\tInode %2d: %s\n", dir
[j
].d_ino
, dir
[j
].d_name
);
1196 if (inode2
[i
].d2_mode
!= 0) {
1197 printf("Inode %2d: mode=", k
);
1198 printf("%06o", inode2
[i
].d2_mode
);
1199 printf(" uid=%2d gid=%2d size=",
1200 inode2
[i
].d2_uid
, inode2
[i
].d2_gid
);
1201 printf("%6ld", inode2
[i
].d2_size
);
1202 printf(" zone[0]=%ld\n", inode2
[i
].d2_zone
[0]);
1204 if ((inode2
[i
].d2_mode
& I_TYPE
) == I_DIRECTORY
) {
1205 /* This is a directory */
1206 get_block(inode2
[i
].d2_zone
[0], (char *) dir
);
1207 for (j
= 0; j
< NR_DIR_ENTRIES(block_size
); j
++)
1209 printf("\tInode %2d: %s\n", dir
[j
].d_ino
, dir
[j
].d_name
);
1215 printf("%d inodes used. %d zones used.\n", next_inode
- 1, next_zone
);
1224 /* The first time a block is read, it returns all 0s, unless there has
1225 * been a write. This routine checks to see if a block has been accessed.
1231 if(w
>= umap_array_elements
) {
1232 pexit("umap array too small - this can't happen");
1236 r
= (umap_array
[w
] & mask
? 1 : 0);
1237 umap_array
[w
] |= mask
;
1244 "Usage: %s [-12dlot] [-b blocks] [-i inodes] [-B blocksize] special [proto]\n",
1249 /*================================================================
1250 * get_block & put_block for MS-DOS
1251 *===============================================================*/
1255 * These are the get_block and put_block routines
1256 * when compiling & running mkfs.c under MS-DOS.
1258 * It requires the (asembler) routines absread & abswrite
1259 * from the file diskio.asm. Since these routines just do
1260 * as they are told (read & write the sector specified),
1261 * a local cache is used to minimize the i/o-overhead for
1262 * frequently used blocks.
1264 * The global variable "file" determines whether the output
1265 * is to a disk-device or to a binary file.
1269 #define PH_SECTSIZE 512 /* size of a physical disk-sector */
1272 char *derrtab
[14] = {
1274 "disk is read-only",
1279 "internal error: bad request structure length",
1281 "unknown media type",
1283 "printer out of paper (?)",
1289 #define CACHE_SIZE 20 /* 20 block-buffers */
1293 char blockbuf
[BLOCK_SIZE
];
1297 } cache
[CACHE_SIZE
];
1300 void special(string
)
1304 if (string
[1] == ':' && string
[2] == 0) {
1305 /* Format: d: or d:fname */
1306 disk
= (string
[0] & ~32) - 'A';
1307 if (disk
> 1 && !override
) /* safety precaution */
1308 pexit("Bad drive specifier for special");
1311 if ((fd
= creat(string
, BWRITE
)) == 0)
1312 pexit("Can't open special file");
1316 void get_block(n
, buf
)
1320 /* Get a block to the user */
1321 struct cache
*bp
, *fp
;
1323 /* First access returns a zero block */
1324 if (read_and_set(n
) == 0) {
1325 copy(zero
, buf
, block_size
);
1329 /* Look for block in cache */
1331 for (bp
= cache
; bp
< &cache
[CACHE_SIZE
]; bp
++) {
1332 if (bp
->blocknum
== n
) {
1333 copy(bp
, buf
, block_size
);
1338 /* Remember clean block */
1341 if (fp
->usecnt
> bp
->usecnt
) fp
= bp
;
1346 /* Block not in cache, get it */
1348 /* No clean buf, flush one */
1349 for (bp
= cache
, fp
= cache
; bp
< &cache
[CACHE_SIZE
]; bp
++)
1350 if (fp
->usecnt
> bp
->usecnt
) fp
= bp
;
1351 mx_write(fp
->blocknum
, fp
);
1357 copy(fp
, buf
, block_size
);
1360 void put_block(n
, buf
)
1364 /* Accept block from user */
1365 struct cache
*fp
, *bp
;
1367 (void) read_and_set(n
);
1369 /* Look for block in cache */
1371 for (bp
= cache
; bp
< &cache
[CACHE_SIZE
]; bp
++) {
1372 if (bp
->blocknum
== n
) {
1373 copy(buf
, bp
, block_size
);
1378 /* Remember clean block */
1381 if (fp
->usecnt
> bp
->usecnt
) fp
= bp
;
1386 /* Block not in cache */
1388 /* No clean buf, flush one */
1389 for (bp
= cache
, fp
= cache
; bp
< &cache
[CACHE_SIZE
]; bp
++)
1390 if (fp
->usecnt
> bp
->usecnt
) fp
= bp
;
1391 mx_write(fp
->blocknum
, fp
);
1396 copy(buf
, fp
, block_size
);
1402 for (bp
= cache
; bp
< &cache
[CACHE_SIZE
]; bp
++) bp
->blocknum
= -1;
1407 /* Flush all dirty blocks to disk */
1410 for (bp
= cache
; bp
< &cache
[CACHE_SIZE
]; bp
++)
1412 mx_write(bp
->blocknum
, bp
);
1417 /*==================================================================
1418 * hard read & write etc.
1419 *=================================================================*/
1420 #define MAX_RETRIES 5
1423 void mx_read(blocknr
, buf
)
1428 /* Read the requested MINIX-block in core */
1429 char (*bp
)[PH_SECTSIZE
];
1430 int sectnum
, retries
, err
;
1433 lseek(fd
, (off_t
) blocknr
* block_size
, 0);
1434 if (read(fd
, buf
, block_size
) != block_size
)
1435 pexit("mx_read: error reading file");
1437 sectnum
= blocknr
* (block_size
/ PH_SECTSIZE
);
1438 for (bp
= buf
; bp
< &buf
[block_size
]; bp
++) {
1439 retries
= MAX_RETRIES
;
1441 err
= absread(disk
, sectnum
, bp
);
1442 while (err
&& --retries
);
1447 dexit("mx_read", sectnum
, err
);
1453 void mx_write(blocknr
, buf
)
1457 /* Write the MINIX-block to disk */
1458 char (*bp
)[PH_SECTSIZE
];
1459 int retries
, sectnum
, err
;
1462 lseek(fd
, blocknr
* block_size
, 0);
1463 if (write(fd
, buf
, block_size
) != block_size
) {
1464 pexit("mx_write: error writing file");
1467 sectnum
= blocknr
* (block_size
/ PH_SECTSIZE
);
1468 for (bp
= buf
; bp
< &buf
[block_size
]; bp
++) {
1469 retries
= MAX_RETRIES
;
1471 err
= abswrite(disk
, sectnum
, bp
);
1472 } while (err
&& --retries
);
1477 dexit("mx_write", sectnum
, err
);
1484 void dexit(s
, sectnum
, err
)
1488 printf("Error: %s, sector: %d, code: %d, meaning: %s\n",
1489 s
, sectnum
, err
, derrtab
[err
]);
1495 /*================================================================
1496 * get_block & put_block for UNIX
1497 *===============================================================*/
1500 void special(string
)
1503 fd
= creat(string
, 0777);
1505 fd
= open(string
, O_RDWR
);
1506 if (fd
< 0) pexit("Can't open special file");
1507 #if (MACHINE == ATARI)
1509 struct stat statbuf
;
1511 if (fstat(fd
, &statbuf
) < 0) return;
1512 isdev
= (statbuf
.st_mode
& S_IFMT
) == S_IFCHR
1514 (statbuf
.st_mode
& S_IFMT
) == S_IFBLK
1522 void get_block(n
, buf
)
1530 /* First access returns a zero block */
1531 if (read_and_set(n
) == 0) {
1532 copy(zero
, buf
, block_size
);
1535 lseek64(fd
, mul64u(n
, block_size
), SEEK_SET
, NULL
);
1536 k
= read(fd
, buf
, block_size
);
1537 if (k
!= block_size
) {
1538 pexit("get_block couldn't read");
1542 void get_super_block(buf
)
1549 if(lseek(fd
, (off_t
) SUPER_BLOCK_BYTES
, SEEK_SET
) < 0) {
1551 pexit("seek failed");
1553 k
= read(fd
, buf
, _STATIC_BLOCK_SIZE
);
1554 if (k
!= _STATIC_BLOCK_SIZE
) {
1555 pexit("get_super_block couldn't read");
1559 void put_block(n
, buf
)
1563 /* Write a block. */
1565 (void) read_and_set(n
);
1567 /* XXX - check other lseeks too. */
1568 if (lseek64(fd
, mul64u(n
, block_size
), SEEK_SET
, NULL
) == (off_t
) -1) {
1569 pexit("put_block couldn't seek");
1571 if (write(fd
, buf
, block_size
) != block_size
) {
1572 pexit("put_block couldn't write");
1577 /* Dummy routines to keep source file clean from #ifdefs */