1433d6423SLionel Sambuc /* mkfs - make the MINIX filesystem Authors: Tanenbaum et al. */ 2433d6423SLionel Sambuc 3433d6423SLionel Sambuc /* Authors: Andy Tanenbaum, Paul Ogilvie, Frans Meulenbroeks, Bruce Evans */ 4433d6423SLionel Sambuc 5433d6423SLionel Sambuc #if HAVE_NBTOOL_CONFIG_H 6433d6423SLionel Sambuc #include "nbtool_config.h" 7433d6423SLionel Sambuc #endif 8433d6423SLionel Sambuc 9433d6423SLionel Sambuc #include <sys/cdefs.h> 10433d6423SLionel Sambuc #include <sys/types.h> 11433d6423SLionel Sambuc #include <sys/stat.h> 12433d6423SLionel Sambuc 13433d6423SLionel Sambuc #if defined(__minix) 14433d6423SLionel Sambuc #include <minix/minlib.h> 15433d6423SLionel Sambuc #include <minix/partition.h> 16433d6423SLionel Sambuc #include <sys/ioctl.h> 17433d6423SLionel Sambuc #endif 18433d6423SLionel Sambuc 19433d6423SLionel Sambuc #include <assert.h> 20433d6423SLionel Sambuc #include <err.h> 21433d6423SLionel Sambuc #include <errno.h> 22433d6423SLionel Sambuc #include <fcntl.h> 23433d6423SLionel Sambuc #include <limits.h> 24433d6423SLionel Sambuc #include <stdarg.h> 25433d6423SLionel Sambuc #include <stdint.h> 26433d6423SLionel Sambuc #include <stdio.h> 27433d6423SLionel Sambuc #include <stdlib.h> 28433d6423SLionel Sambuc #include <string.h> 29433d6423SLionel Sambuc #include <time.h> 30433d6423SLionel Sambuc #include <unistd.h> 31433d6423SLionel Sambuc 32433d6423SLionel Sambuc /* Definition of the file system layout: */ 33433d6423SLionel Sambuc #include "const.h" 34433d6423SLionel Sambuc #include "type.h" 35433d6423SLionel Sambuc #include "mfsdir.h" 36433d6423SLionel Sambuc #include "super.h" 37433d6423SLionel Sambuc 38433d6423SLionel Sambuc #define INODE_MAP START_BLOCK 39433d6423SLionel Sambuc /* inode zone indexes pointing to single and double indirect zones */ 40433d6423SLionel Sambuc #define S_INDIRECT_IDX (NR_DZONES) 41433d6423SLionel Sambuc #define D_INDIRECT_IDX (NR_DZONES+1) 42433d6423SLionel Sambuc 43433d6423SLionel Sambuc 44433d6423SLionel Sambuc #define MAX_TOKENS 10 45433d6423SLionel Sambuc #define LINE_LEN 200 46433d6423SLionel Sambuc /* XXX why do we not use 0 / SU_ID ? */ 47433d6423SLionel Sambuc #define BIN 2 48433d6423SLionel Sambuc #define BINGRP 2 49433d6423SLionel Sambuc 50433d6423SLionel Sambuc /* some Minix specific types that do not conflict with Posix */ 51433d6423SLionel Sambuc #ifndef block_t 52433d6423SLionel Sambuc typedef uint32_t block_t; /* block number */ 53433d6423SLionel Sambuc #endif 54433d6423SLionel Sambuc #ifndef zone_t 55433d6423SLionel Sambuc typedef uint32_t zone_t; /* zone number */ 56433d6423SLionel Sambuc #endif 57433d6423SLionel Sambuc #ifndef bit_t 58433d6423SLionel Sambuc typedef uint32_t bit_t; /* bit number in a bit map */ 59433d6423SLionel Sambuc #endif 60433d6423SLionel Sambuc #ifndef bitchunk_t 61433d6423SLionel Sambuc typedef uint32_t bitchunk_t; /* collection of bits in a bitmap */ 62433d6423SLionel Sambuc #endif 63433d6423SLionel Sambuc 64433d6423SLionel Sambuc struct fs_size { 65433d6423SLionel Sambuc ino_t inocount; /* amount of inodes */ 66433d6423SLionel Sambuc zone_t zonecount; /* amount of zones */ 67433d6423SLionel Sambuc block_t blockcount; /* amount of blocks */ 68433d6423SLionel Sambuc }; 69433d6423SLionel Sambuc 70433d6423SLionel Sambuc extern char *optarg; 71433d6423SLionel Sambuc extern int optind; 72433d6423SLionel Sambuc 73433d6423SLionel Sambuc block_t nrblocks; 74433d6423SLionel Sambuc int zone_per_block, zone_shift = 0; 75433d6423SLionel Sambuc zone_t next_zone, zoff, nr_indirzones; 76433d6423SLionel Sambuc int inodes_per_block, indir_per_block, indir_per_zone; 77433d6423SLionel Sambuc unsigned int zone_size; 78433d6423SLionel Sambuc ino_t nrinodes, inode_offset, next_inode; 79433d6423SLionel Sambuc int lct = 0, fd, print = 0; 80433d6423SLionel Sambuc int simple = 0, dflag = 0, verbose = 0; 81433d6423SLionel Sambuc int donttest; /* skip test if it fits on medium */ 82433d6423SLionel Sambuc char *progname; 83433d6423SLionel Sambuc uint64_t fs_offset_bytes, fs_offset_blocks, written_fs_size = 0; 84433d6423SLionel Sambuc 85433d6423SLionel Sambuc time_t current_time; 86433d6423SLionel Sambuc char *zero; 87433d6423SLionel Sambuc unsigned char *umap_array; /* bit map tells if block read yet */ 88433d6423SLionel Sambuc size_t umap_array_elements; 89433d6423SLionel Sambuc block_t zone_map; /* where is zone map? (depends on # inodes) */ 90433d6423SLionel Sambuc #ifndef MFS_STATIC_BLOCK_SIZE 91433d6423SLionel Sambuc size_t block_size; 92433d6423SLionel Sambuc #else 93433d6423SLionel Sambuc #define block_size MFS_STATIC_BLOCK_SIZE 94433d6423SLionel Sambuc #endif 95433d6423SLionel Sambuc 96433d6423SLionel Sambuc FILE *proto; 97433d6423SLionel Sambuc 98433d6423SLionel Sambuc int main(int argc, char **argv); 99433d6423SLionel Sambuc void detect_fs_size(struct fs_size * fssize); 100433d6423SLionel Sambuc void sizeup_dir(struct fs_size * fssize); 101433d6423SLionel Sambuc block_t sizeup(char *device); 102433d6423SLionel Sambuc static int bitmapsize(bit_t nr_bits, size_t blk_size); 103433d6423SLionel Sambuc void super(zone_t zones, ino_t inodes); 104433d6423SLionel Sambuc void rootdir(ino_t inode); 105433d6423SLionel Sambuc void enter_symlink(ino_t inode, char *link); 106433d6423SLionel Sambuc int dir_try_enter(zone_t z, ino_t child, char const *name); 107433d6423SLionel Sambuc void eat_dir(ino_t parent); 108433d6423SLionel Sambuc void eat_file(ino_t inode, int f); 109433d6423SLionel Sambuc void enter_dir(ino_t parent, char const *name, ino_t child); 110433d6423SLionel Sambuc void add_zone(ino_t n, zone_t z, size_t bytes, time_t cur_time); 111433d6423SLionel Sambuc void incr_link(ino_t n); 112433d6423SLionel Sambuc void incr_size(ino_t n, size_t count); 113433d6423SLionel Sambuc static ino_t alloc_inode(int mode, int usrid, int grpid); 114433d6423SLionel Sambuc static zone_t alloc_zone(void); 115433d6423SLionel Sambuc void insert_bit(block_t block, bit_t bit); 116433d6423SLionel Sambuc int mode_con(char *p); 117433d6423SLionel Sambuc void get_line(char line[LINE_LEN], char *parse[MAX_TOKENS]); 118433d6423SLionel Sambuc void check_mtab(const char *devname); 119433d6423SLionel Sambuc time_t file_time(int f); 120433d6423SLionel Sambuc __dead void pexit(char const *s, ...) __printflike(1,2); 121433d6423SLionel Sambuc void *alloc_block(void); 122433d6423SLionel Sambuc void print_fs(void); 123433d6423SLionel Sambuc int read_and_set(block_t n); 124433d6423SLionel Sambuc void special(char *string, int insertmode); 125433d6423SLionel Sambuc __dead void usage(void); 126433d6423SLionel Sambuc void get_block(block_t n, void *buf); 127433d6423SLionel Sambuc void get_super_block(void *buf); 128433d6423SLionel Sambuc void put_block(block_t n, void *buf); 129433d6423SLionel Sambuc static uint64_t mkfs_seek(uint64_t pos, int whence); 130433d6423SLionel Sambuc static ssize_t mkfs_write(void * buf, size_t count); 131433d6423SLionel Sambuc 132433d6423SLionel Sambuc /*================================================================ 133433d6423SLionel Sambuc * mkfs - make filesystem 134433d6423SLionel Sambuc *===============================================================*/ 135433d6423SLionel Sambuc int 136433d6423SLionel Sambuc main(int argc, char *argv[]) 137433d6423SLionel Sambuc { 138433d6423SLionel Sambuc int nread, mode, usrid, grpid, ch, extra_space_percent, Tflag = 0; 139433d6423SLionel Sambuc block_t blocks, maxblocks, bblocks; 140433d6423SLionel Sambuc ino_t inodes, root_inum; 141433d6423SLionel Sambuc char *token[MAX_TOKENS], line[LINE_LEN], *sfx; 142433d6423SLionel Sambuc struct fs_size fssize; 143433d6423SLionel Sambuc int insertmode = 0; 144433d6423SLionel Sambuc 145433d6423SLionel Sambuc progname = argv[0]; 146433d6423SLionel Sambuc 147433d6423SLionel Sambuc /* Process switches. */ 148433d6423SLionel Sambuc blocks = 0; 149433d6423SLionel Sambuc inodes = 0; 150433d6423SLionel Sambuc bblocks = 0; 151433d6423SLionel Sambuc #ifndef MFS_STATIC_BLOCK_SIZE 152433d6423SLionel Sambuc block_size = 0; 153433d6423SLionel Sambuc #endif 154433d6423SLionel Sambuc zone_shift = 0; 155433d6423SLionel Sambuc extra_space_percent = 0; 156433d6423SLionel Sambuc while ((ch = getopt(argc, argv, "B:b:di:ltvx:z:I:T:")) != EOF) 157433d6423SLionel Sambuc switch (ch) { 158433d6423SLionel Sambuc #ifndef MFS_STATIC_BLOCK_SIZE 159433d6423SLionel Sambuc case 'B': 160433d6423SLionel Sambuc block_size = strtoul(optarg, &sfx, 0); 161433d6423SLionel Sambuc switch(*sfx) { 162433d6423SLionel Sambuc case 'b': case 'B': /* bytes; NetBSD-compatible */ 163433d6423SLionel Sambuc case '\0': break; 164433d6423SLionel Sambuc case 'K': 165433d6423SLionel Sambuc case 'k': block_size*=1024; break; 166433d6423SLionel Sambuc case 's': block_size*=SECTOR_SIZE; break; 167433d6423SLionel Sambuc default: usage(); 168433d6423SLionel Sambuc } 169433d6423SLionel Sambuc break; 170433d6423SLionel Sambuc #else 171433d6423SLionel Sambuc case 'B': 172433d6423SLionel Sambuc if (block_size != strtoul(optarg, (char **) NULL, 0)) 173433d6423SLionel Sambuc errx(4, "block size must be exactly %d bytes", 174433d6423SLionel Sambuc MFS_STATIC_BLOCK_SIZE); 175433d6423SLionel Sambuc break; 176433d6423SLionel Sambuc (void)sfx; /* shut up warnings about unused variable...*/ 177433d6423SLionel Sambuc #endif 178433d6423SLionel Sambuc case 'I': 179433d6423SLionel Sambuc fs_offset_bytes = strtoul(optarg, (char **) NULL, 0); 180433d6423SLionel Sambuc insertmode = 1; 181433d6423SLionel Sambuc break; 182433d6423SLionel Sambuc case 'b': 183433d6423SLionel Sambuc blocks = bblocks = strtoul(optarg, (char **) NULL, 0); 184433d6423SLionel Sambuc break; 185433d6423SLionel Sambuc case 'T': 186433d6423SLionel Sambuc Tflag = 1; 187433d6423SLionel Sambuc current_time = strtoul(optarg, (char **) NULL, 0); 188433d6423SLionel Sambuc break; 189433d6423SLionel Sambuc case 'd': 190433d6423SLionel Sambuc dflag = 1; 191433d6423SLionel Sambuc break; 192433d6423SLionel Sambuc case 'i': 193433d6423SLionel Sambuc inodes = strtoul(optarg, (char **) NULL, 0); 194433d6423SLionel Sambuc break; 195433d6423SLionel Sambuc case 'l': print = 1; break; 196433d6423SLionel Sambuc case 't': donttest = 1; break; 197433d6423SLionel Sambuc case 'v': ++verbose; break; 198433d6423SLionel Sambuc case 'x': extra_space_percent = atoi(optarg); break; 199433d6423SLionel Sambuc case 'z': zone_shift = atoi(optarg); break; 200433d6423SLionel Sambuc default: usage(); 201433d6423SLionel Sambuc } 202433d6423SLionel Sambuc 203433d6423SLionel Sambuc if (argc == optind) usage(); 204433d6423SLionel Sambuc 205433d6423SLionel Sambuc /* Get the current time, set it to the mod time of the binary of 206433d6423SLionel Sambuc * mkfs itself when the -d flag is used. The 'current' time is put into 207433d6423SLionel Sambuc * the i_mtimes of all the files. This -d feature is useful when 208433d6423SLionel Sambuc * producing a set of file systems, and one wants all the times to be 209433d6423SLionel Sambuc * identical. First you set the time of the mkfs binary to what you 210433d6423SLionel Sambuc * want, then go. 211433d6423SLionel Sambuc */ 212433d6423SLionel Sambuc if(Tflag) { 213433d6423SLionel Sambuc if(dflag) 214433d6423SLionel Sambuc errx(1, "-T and -d both specify a time and so are mutually exclusive"); 215433d6423SLionel Sambuc } else if(dflag) { 216433d6423SLionel Sambuc struct stat statbuf; 217433d6423SLionel Sambuc if (stat(progname, &statbuf)) { 218433d6423SLionel Sambuc err(1, "stat of itself"); 219433d6423SLionel Sambuc } 220433d6423SLionel Sambuc current_time = statbuf.st_mtime; 221433d6423SLionel Sambuc } else { 222433d6423SLionel Sambuc current_time = time((time_t *) 0); /* time mkfs is being run */ 223433d6423SLionel Sambuc } 224433d6423SLionel Sambuc 225433d6423SLionel Sambuc /* Percentage of extra size must be nonnegative. 226433d6423SLionel Sambuc * It can legitimately be bigger than 100 but has to make some sort of sense. 227433d6423SLionel Sambuc */ 228433d6423SLionel Sambuc if(extra_space_percent < 0 || extra_space_percent > 2000) usage(); 229433d6423SLionel Sambuc 230433d6423SLionel Sambuc #ifdef DEFAULT_BLOCK_SIZE 231433d6423SLionel Sambuc if(!block_size) block_size = DEFAULT_BLOCK_SIZE; 232433d6423SLionel Sambuc #endif 233433d6423SLionel Sambuc if (block_size % SECTOR_SIZE) 234433d6423SLionel Sambuc errx(4, "block size must be multiple of sector (%d bytes)", SECTOR_SIZE); 235433d6423SLionel Sambuc #ifdef MIN_BLOCK_SIZE 236433d6423SLionel Sambuc if (block_size < MIN_BLOCK_SIZE) 237433d6423SLionel Sambuc errx(4, "block size must be at least %d bytes", MIN_BLOCK_SIZE); 238433d6423SLionel Sambuc #endif 239433d6423SLionel Sambuc #ifdef MAX_BLOCK_SIZE 240433d6423SLionel Sambuc if (block_size > MAX_BLOCK_SIZE) 241433d6423SLionel Sambuc errx(4, "block size must be at most %d bytes", MAX_BLOCK_SIZE); 242433d6423SLionel Sambuc #endif 243433d6423SLionel Sambuc if(block_size%INODE_SIZE) 244433d6423SLionel Sambuc errx(4, "block size must be a multiple of inode size (%d bytes)", INODE_SIZE); 245433d6423SLionel Sambuc 246433d6423SLionel Sambuc if(zone_shift < 0 || zone_shift > 14) 247433d6423SLionel Sambuc errx(4, "zone_shift must be a small non-negative integer"); 248433d6423SLionel Sambuc zone_per_block = 1 << zone_shift; /* nr of blocks per zone */ 249433d6423SLionel Sambuc 250433d6423SLionel Sambuc inodes_per_block = INODES_PER_BLOCK(block_size); 251433d6423SLionel Sambuc indir_per_block = INDIRECTS(block_size); 252433d6423SLionel Sambuc indir_per_zone = INDIRECTS(block_size) << zone_shift; 253433d6423SLionel Sambuc /* number of file zones we can address directly and with a single indirect*/ 254433d6423SLionel Sambuc nr_indirzones = NR_DZONES + indir_per_zone; 255433d6423SLionel Sambuc zone_size = block_size << zone_shift; 256433d6423SLionel Sambuc /* Checks for an overflow: only with very big block size */ 257433d6423SLionel Sambuc if (zone_size <= 0) 258433d6423SLionel Sambuc errx(4, "Zones are too big for this program; smaller -B or -z, please!"); 259433d6423SLionel Sambuc 260433d6423SLionel Sambuc /* now that the block size is known, do buffer allocations where 261433d6423SLionel Sambuc * possible. 262433d6423SLionel Sambuc */ 263433d6423SLionel Sambuc zero = alloc_block(); 264433d6423SLionel Sambuc 265433d6423SLionel Sambuc fs_offset_blocks = roundup(fs_offset_bytes, block_size) / block_size; 266433d6423SLionel Sambuc 267433d6423SLionel Sambuc /* Determine the size of the device if not specified as -b or proto. */ 268433d6423SLionel Sambuc maxblocks = sizeup(argv[optind]); 269433d6423SLionel Sambuc if (bblocks != 0 && bblocks + fs_offset_blocks > maxblocks && !insertmode) { 270433d6423SLionel Sambuc errx(4, "Given size -b %d exeeds device capacity(%d)\n", bblocks, maxblocks); 271433d6423SLionel Sambuc } 272433d6423SLionel Sambuc 273433d6423SLionel Sambuc if (argc - optind == 1 && bblocks == 0) { 274433d6423SLionel Sambuc blocks = maxblocks; 275433d6423SLionel Sambuc /* blocks == 0 is checked later, but leads to a funny way of 276433d6423SLionel Sambuc * reporting a 0-sized device (displays usage). 277433d6423SLionel Sambuc */ 278433d6423SLionel Sambuc if(blocks < 1) { 279433d6423SLionel Sambuc errx(1, "zero size device."); 280433d6423SLionel Sambuc } 281433d6423SLionel Sambuc } 282433d6423SLionel Sambuc 283433d6423SLionel Sambuc /* The remaining args must be 'special proto', or just 'special' if the 284433d6423SLionel Sambuc * no. of blocks has already been specified. 285433d6423SLionel Sambuc */ 286433d6423SLionel Sambuc if (argc - optind != 2 && (argc - optind != 1 || blocks == 0)) usage(); 287433d6423SLionel Sambuc 288433d6423SLionel Sambuc if (maxblocks && blocks > maxblocks && !insertmode) { 289433d6423SLionel Sambuc errx(1, "%s: number of blocks too large for device.", argv[optind]); 290433d6423SLionel Sambuc } 291433d6423SLionel Sambuc 292433d6423SLionel Sambuc /* Check special. */ 293433d6423SLionel Sambuc check_mtab(argv[optind]); 294433d6423SLionel Sambuc 295433d6423SLionel Sambuc /* Check and start processing proto. */ 296433d6423SLionel Sambuc optarg = argv[++optind]; 297433d6423SLionel Sambuc if (optind < argc && (proto = fopen(optarg, "r")) != NULL) { 298433d6423SLionel Sambuc /* Prototype file is readable. */ 299433d6423SLionel Sambuc lct = 1; 300433d6423SLionel Sambuc get_line(line, token); /* skip boot block info */ 301433d6423SLionel Sambuc 302433d6423SLionel Sambuc /* Read the line with the block and inode counts. */ 303433d6423SLionel Sambuc get_line(line, token); 304433d6423SLionel Sambuc if (bblocks == 0){ 305433d6423SLionel Sambuc blocks = strtol(token[0], (char **) NULL, 10); 306433d6423SLionel Sambuc } else { 307433d6423SLionel Sambuc if(bblocks < strtol(token[0], (char **) NULL, 10)) { 308433d6423SLionel Sambuc errx(1, "%s: number of blocks given as parameter(%d)" 309cd34841dSBen Gras " is too small for given proto file(%ld).", 310433d6423SLionel Sambuc argv[optind], bblocks, 311433d6423SLionel Sambuc strtol(token[0], (char **) NULL, 10)); 312433d6423SLionel Sambuc }; 313433d6423SLionel Sambuc } 314433d6423SLionel Sambuc inodes = strtol(token[1], (char **) NULL, 10); 315433d6423SLionel Sambuc 316433d6423SLionel Sambuc /* Process mode line for root directory. */ 317433d6423SLionel Sambuc get_line(line, token); 318433d6423SLionel Sambuc mode = mode_con(token[0]); 319433d6423SLionel Sambuc usrid = atoi(token[1]); 320433d6423SLionel Sambuc grpid = atoi(token[2]); 321433d6423SLionel Sambuc 322433d6423SLionel Sambuc if(blocks <= 0 && inodes <= 0){ 323433d6423SLionel Sambuc detect_fs_size(&fssize); 324433d6423SLionel Sambuc blocks = fssize.blockcount; 325433d6423SLionel Sambuc inodes = fssize.inocount; 326433d6423SLionel Sambuc blocks += blocks*extra_space_percent/100; 327433d6423SLionel Sambuc inodes += inodes*extra_space_percent/100; 328433d6423SLionel Sambuc /* XXX is it OK to write on stdout? Use warn() instead? Also consider using verbose */ 329433d6423SLionel Sambuc fprintf(stderr, "dynamically sized filesystem: %u blocks, %u inodes\n", 330433d6423SLionel Sambuc (unsigned int) blocks, (unsigned int) inodes); 331433d6423SLionel Sambuc } 332433d6423SLionel Sambuc } else { 333433d6423SLionel Sambuc lct = 0; 334433d6423SLionel Sambuc if (optind < argc) { 335433d6423SLionel Sambuc /* Maybe the prototype file is just a size. Check. */ 336433d6423SLionel Sambuc blocks = strtoul(optarg, (char **) NULL, 0); 337433d6423SLionel Sambuc if (blocks == 0) errx(2, "Can't open prototype file"); 338433d6423SLionel Sambuc } 339433d6423SLionel Sambuc 340433d6423SLionel Sambuc /* Make simple file system of the given size, using defaults. */ 341433d6423SLionel Sambuc mode = 040777; 342433d6423SLionel Sambuc usrid = BIN; 343433d6423SLionel Sambuc grpid = BINGRP; 344433d6423SLionel Sambuc simple = 1; 345433d6423SLionel Sambuc } 346433d6423SLionel Sambuc 347433d6423SLionel Sambuc if (inodes == 0) { 348433d6423SLionel Sambuc long long kb = ((unsigned long long)blocks*block_size) / 1024; 349433d6423SLionel Sambuc 350433d6423SLionel Sambuc inodes = kb / 2; 351433d6423SLionel Sambuc if (kb >= 100000) inodes = kb / 4; 352433d6423SLionel Sambuc if (kb >= 1000000) inodes = kb / 6; 353433d6423SLionel Sambuc if (kb >= 10000000) inodes = kb / 8; 354433d6423SLionel Sambuc if (kb >= 100000000) inodes = kb / 10; 355433d6423SLionel Sambuc if (kb >= 1000000000) inodes = kb / 12; 356433d6423SLionel Sambuc /* XXX check overflow: with very large number of blocks, this results in insanely large number of inodes */ 357433d6423SLionel Sambuc /* XXX check underflow (if/when ino_t is signed), else the message below will look strange */ 358433d6423SLionel Sambuc 359433d6423SLionel Sambuc /* round up to fill inode block */ 360433d6423SLionel Sambuc inodes += inodes_per_block - 1; 361433d6423SLionel Sambuc inodes = inodes / inodes_per_block * inodes_per_block; 362433d6423SLionel Sambuc } 363433d6423SLionel Sambuc 364433d6423SLionel Sambuc if (blocks < 5) errx(1, "Block count too small"); 365433d6423SLionel Sambuc if (inodes < 1) errx(1, "Inode count too small"); 366433d6423SLionel Sambuc 367433d6423SLionel Sambuc nrblocks = blocks; 368433d6423SLionel Sambuc nrinodes = inodes; 369433d6423SLionel Sambuc 370433d6423SLionel Sambuc umap_array_elements = 1 + blocks/8; 371433d6423SLionel Sambuc if(!(umap_array = malloc(umap_array_elements))) 372433d6423SLionel Sambuc err(1, "can't allocate block bitmap (%u bytes).", 373433d6423SLionel Sambuc (unsigned)umap_array_elements); 374433d6423SLionel Sambuc 375433d6423SLionel Sambuc /* Open special. */ 376433d6423SLionel Sambuc special(argv[--optind], insertmode); 377433d6423SLionel Sambuc 378433d6423SLionel Sambuc if (!donttest) { 379433d6423SLionel Sambuc uint16_t *testb; 380433d6423SLionel Sambuc ssize_t w; 381433d6423SLionel Sambuc 382433d6423SLionel Sambuc testb = alloc_block(); 383433d6423SLionel Sambuc 384433d6423SLionel Sambuc /* Try writing the last block of partition or diskette. */ 385433d6423SLionel Sambuc mkfs_seek((uint64_t)(blocks - 1) * block_size, SEEK_SET); 386433d6423SLionel Sambuc testb[0] = 0x3245; 387433d6423SLionel Sambuc testb[1] = 0x11FF; 388433d6423SLionel Sambuc testb[block_size/2-1] = 0x1F2F; 389433d6423SLionel Sambuc w=mkfs_write(testb, block_size); 390433d6423SLionel Sambuc sync(); /* flush write, so if error next read fails */ 391433d6423SLionel Sambuc mkfs_seek((uint64_t)(blocks - 1) * block_size, SEEK_SET); 392433d6423SLionel Sambuc testb[0] = 0; 393433d6423SLionel Sambuc testb[1] = 0; 394433d6423SLionel Sambuc testb[block_size/2-1] = 0; 395433d6423SLionel Sambuc nread = read(fd, testb, block_size); 396433d6423SLionel Sambuc if (nread != block_size || testb[0] != 0x3245 || testb[1] != 0x11FF || 397433d6423SLionel Sambuc testb[block_size/2-1] != 0x1F2F) { 398433d6423SLionel Sambuc warn("nread = %d\n", nread); 399433d6423SLionel Sambuc warnx("testb = 0x%x 0x%x 0x%x\n", 400433d6423SLionel Sambuc testb[0], testb[1], testb[block_size-1]); 401433d6423SLionel Sambuc errx(1, "File system is too big for minor device (read)"); 402433d6423SLionel Sambuc } 403433d6423SLionel Sambuc mkfs_seek((uint64_t)(blocks - 1) * block_size, SEEK_SET); 404433d6423SLionel Sambuc testb[0] = 0; 405433d6423SLionel Sambuc testb[1] = 0; 406433d6423SLionel Sambuc testb[block_size/2-1] = 0; 407433d6423SLionel Sambuc mkfs_write(testb, block_size); 408433d6423SLionel Sambuc mkfs_seek(0L, SEEK_SET); 409433d6423SLionel Sambuc free(testb); 410433d6423SLionel Sambuc } 411433d6423SLionel Sambuc 412433d6423SLionel Sambuc /* Make the file-system */ 413433d6423SLionel Sambuc 414433d6423SLionel Sambuc put_block(BOOT_BLOCK, zero); /* Write a null boot block. */ 415433d6423SLionel Sambuc put_block(BOOT_BLOCK+1, zero); /* Write another null block. */ 416433d6423SLionel Sambuc 417433d6423SLionel Sambuc super(nrblocks >> zone_shift, inodes); 418433d6423SLionel Sambuc 419433d6423SLionel Sambuc root_inum = alloc_inode(mode, usrid, grpid); 420433d6423SLionel Sambuc rootdir(root_inum); 421433d6423SLionel Sambuc if (simple == 0) eat_dir(root_inum); 422433d6423SLionel Sambuc 423433d6423SLionel Sambuc if (print) print_fs(); 424433d6423SLionel Sambuc else if (verbose > 1) { 425433d6423SLionel Sambuc if (zone_shift) 426433d6423SLionel Sambuc fprintf(stderr, "%d inodes used. %u zones (%u blocks) used.\n", 427433d6423SLionel Sambuc (int)next_inode-1, next_zone, next_zone*zone_per_block); 428433d6423SLionel Sambuc else 429433d6423SLionel Sambuc fprintf(stderr, "%d inodes used. %u zones used.\n", 430433d6423SLionel Sambuc (int)next_inode-1, next_zone); 431433d6423SLionel Sambuc } 432433d6423SLionel Sambuc 433*7c48de6cSDavid van Moolenbroek if(insertmode) printf("%"PRIu64"\n", written_fs_size); 434433d6423SLionel Sambuc 435433d6423SLionel Sambuc return(0); 436433d6423SLionel Sambuc 437433d6423SLionel Sambuc /* NOTREACHED */ 438433d6423SLionel Sambuc } /* end main */ 439433d6423SLionel Sambuc 440433d6423SLionel Sambuc /*================================================================ 441433d6423SLionel Sambuc * detect_fs_size - determine image size dynamically 442433d6423SLionel Sambuc *===============================================================*/ 443433d6423SLionel Sambuc void 444433d6423SLionel Sambuc detect_fs_size(struct fs_size * fssize) 445433d6423SLionel Sambuc { 446433d6423SLionel Sambuc int prev_lct = lct; 447433d6423SLionel Sambuc off_t point = ftell(proto); 448433d6423SLionel Sambuc block_t initb; 449433d6423SLionel Sambuc zone_t initz; 450433d6423SLionel Sambuc 451433d6423SLionel Sambuc fssize->inocount = 1; /* root directory node */ 452433d6423SLionel Sambuc fssize->zonecount = 0; 453433d6423SLionel Sambuc fssize->blockcount = 0; 454433d6423SLionel Sambuc 455433d6423SLionel Sambuc sizeup_dir(fssize); 456433d6423SLionel Sambuc 457433d6423SLionel Sambuc initb = bitmapsize(1 + fssize->inocount, block_size); 458433d6423SLionel Sambuc initb += bitmapsize(fssize->zonecount, block_size); 459433d6423SLionel Sambuc initb += START_BLOCK; 460433d6423SLionel Sambuc initb += (fssize->inocount + inodes_per_block - 1) / inodes_per_block; 461433d6423SLionel Sambuc initz = (initb + zone_per_block - 1) >> zone_shift; 462433d6423SLionel Sambuc 463433d6423SLionel Sambuc fssize->blockcount = initb+ fssize->zonecount; 464433d6423SLionel Sambuc lct = prev_lct; 465433d6423SLionel Sambuc fseek(proto, point, SEEK_SET); 466433d6423SLionel Sambuc } 467433d6423SLionel Sambuc 468433d6423SLionel Sambuc void 469433d6423SLionel Sambuc sizeup_dir(struct fs_size * fssize) 470433d6423SLionel Sambuc { 471433d6423SLionel Sambuc char *token[MAX_TOKENS], *p; 472433d6423SLionel Sambuc char line[LINE_LEN]; 473433d6423SLionel Sambuc FILE *f; 474433d6423SLionel Sambuc off_t size; 475433d6423SLionel Sambuc int dir_entries = 2; 476433d6423SLionel Sambuc zone_t dir_zones = 0, fzones, indirects; 477433d6423SLionel Sambuc 478433d6423SLionel Sambuc while (1) { 479433d6423SLionel Sambuc get_line(line, token); 480433d6423SLionel Sambuc p = token[0]; 481433d6423SLionel Sambuc if (*p == '$') { 482433d6423SLionel Sambuc dir_zones = (dir_entries / (NR_DIR_ENTRIES(block_size) * zone_per_block)); 483433d6423SLionel Sambuc if(dir_entries % (NR_DIR_ENTRIES(block_size) * zone_per_block)) 484433d6423SLionel Sambuc dir_zones++; 485433d6423SLionel Sambuc if(dir_zones > NR_DZONES) 486433d6423SLionel Sambuc dir_zones++; /* Max single indir */ 487433d6423SLionel Sambuc fssize->zonecount += dir_zones; 488433d6423SLionel Sambuc return; 489433d6423SLionel Sambuc } 490433d6423SLionel Sambuc 491433d6423SLionel Sambuc p = token[1]; 492433d6423SLionel Sambuc fssize->inocount++; 493433d6423SLionel Sambuc dir_entries++; 494433d6423SLionel Sambuc 495433d6423SLionel Sambuc if (*p == 'd') { 496433d6423SLionel Sambuc sizeup_dir(fssize); 497433d6423SLionel Sambuc } else if (*p == 'b' || *p == 'c') { 498433d6423SLionel Sambuc 499433d6423SLionel Sambuc } else if (*p == 's') { 500433d6423SLionel Sambuc fssize->zonecount++; /* Symlink contents is always stored a block */ 501433d6423SLionel Sambuc } else { 502433d6423SLionel Sambuc if ((f = fopen(token[4], "rb")) == NULL) { 503cd34841dSBen Gras /* on minix natively, allow EACCES and skip the entry. 504cd34841dSBen Gras * while crossbuilding, always fail on error. 505cd34841dSBen Gras */ 506cd34841dSBen Gras #ifdef __minix 507cd34841dSBen Gras if(errno == EACCES) 508433d6423SLionel Sambuc warn("dynamic sizing: can't open %s", token[4]); 509cd34841dSBen Gras else 510cd34841dSBen Gras #endif 511cd34841dSBen Gras err(1, "dynamic sizing: can't open %s", token[4]); 512433d6423SLionel Sambuc } else if (fseek(f, 0, SEEK_END) < 0) { 513433d6423SLionel Sambuc pexit("dynamic size detection failed: seek to end of %s", 514433d6423SLionel Sambuc token[4]); 515433d6423SLionel Sambuc } else if ( (size = ftell(f)) == (off_t)(-1)) { 516433d6423SLionel Sambuc pexit("dynamic size detection failed: can't tell size of %s", 517433d6423SLionel Sambuc token[4]); 518433d6423SLionel Sambuc } else { 519433d6423SLionel Sambuc fclose(f); 520433d6423SLionel Sambuc fzones = roundup(size, zone_size) / zone_size; 521433d6423SLionel Sambuc indirects = 0; 522433d6423SLionel Sambuc /* XXX overflow? fzones is u32, size is potentially 64-bit */ 523433d6423SLionel Sambuc if (fzones > NR_DZONES) 524433d6423SLionel Sambuc indirects++; /* single indirect needed */ 525433d6423SLionel Sambuc if (fzones > nr_indirzones) { 526433d6423SLionel Sambuc /* Each further group of 'indir_per_zone' 527433d6423SLionel Sambuc * needs one supplementary indirect zone: 528433d6423SLionel Sambuc */ 529433d6423SLionel Sambuc indirects += roundup(fzones - nr_indirzones, 530433d6423SLionel Sambuc indir_per_zone) / indir_per_zone; 531433d6423SLionel Sambuc indirects++; /* + double indirect needed!*/ 532433d6423SLionel Sambuc } 533433d6423SLionel Sambuc fssize->zonecount += fzones + indirects; 534433d6423SLionel Sambuc } 535433d6423SLionel Sambuc } 536433d6423SLionel Sambuc } 537433d6423SLionel Sambuc } 538433d6423SLionel Sambuc 539433d6423SLionel Sambuc /*================================================================ 540433d6423SLionel Sambuc * sizeup - determine device size 541433d6423SLionel Sambuc *===============================================================*/ 542433d6423SLionel Sambuc block_t 543433d6423SLionel Sambuc sizeup(char * device) 544433d6423SLionel Sambuc { 545433d6423SLionel Sambuc block_t d; 546433d6423SLionel Sambuc #if defined(__minix) 547433d6423SLionel Sambuc uint64_t bytes, resize; 548433d6423SLionel Sambuc uint32_t rem; 549433d6423SLionel Sambuc #else 550433d6423SLionel Sambuc off_t size; 551433d6423SLionel Sambuc #endif 552433d6423SLionel Sambuc 553433d6423SLionel Sambuc 554433d6423SLionel Sambuc if ((fd = open(device, O_RDONLY)) == -1) { 555433d6423SLionel Sambuc if (errno != ENOENT) 556433d6423SLionel Sambuc perror("sizeup open"); 557433d6423SLionel Sambuc return 0; 558433d6423SLionel Sambuc } 559433d6423SLionel Sambuc 560433d6423SLionel Sambuc #if defined(__minix) 561433d6423SLionel Sambuc if(minix_sizeup(device, &bytes) < 0) { 562433d6423SLionel Sambuc perror("sizeup"); 563433d6423SLionel Sambuc return 0; 564433d6423SLionel Sambuc } 565433d6423SLionel Sambuc 566433d6423SLionel Sambuc d = (uint32_t)(bytes / block_size); 567433d6423SLionel Sambuc rem = (uint32_t)(bytes % block_size); 568433d6423SLionel Sambuc 569433d6423SLionel Sambuc resize = ((uint64_t)d * block_size) + rem; 570433d6423SLionel Sambuc if(resize != bytes) { 571433d6423SLionel Sambuc /* Assume block_t is unsigned */ 572433d6423SLionel Sambuc d = (block_t)(-1ul); 573433d6423SLionel Sambuc fprintf(stderr, "%s: truncating FS at %lu blocks\n", 574433d6423SLionel Sambuc progname, (unsigned long)d); 575433d6423SLionel Sambuc } 576433d6423SLionel Sambuc #else 577433d6423SLionel Sambuc size = mkfs_seek(0, SEEK_END); 578433d6423SLionel Sambuc /* Assume block_t is unsigned */ 579433d6423SLionel Sambuc if (size / block_size > (block_t)(-1ul)) { 580433d6423SLionel Sambuc d = (block_t)(-1ul); 581433d6423SLionel Sambuc fprintf(stderr, "%s: truncating FS at %lu blocks\n", 582433d6423SLionel Sambuc progname, (unsigned long)d); 583433d6423SLionel Sambuc } else 584433d6423SLionel Sambuc d = size / block_size; 585433d6423SLionel Sambuc #endif 586433d6423SLionel Sambuc 587433d6423SLionel Sambuc return d; 588433d6423SLionel Sambuc } 589433d6423SLionel Sambuc 590433d6423SLionel Sambuc /* 591433d6423SLionel Sambuc * copied from fslib 592433d6423SLionel Sambuc */ 593433d6423SLionel Sambuc static int 594433d6423SLionel Sambuc bitmapsize(bit_t nr_bits, size_t blk_size) 595433d6423SLionel Sambuc { 596433d6423SLionel Sambuc block_t nr_blocks; 597433d6423SLionel Sambuc 598433d6423SLionel Sambuc nr_blocks = nr_bits / FS_BITS_PER_BLOCK(blk_size); 599433d6423SLionel Sambuc if (nr_blocks * FS_BITS_PER_BLOCK(blk_size) < nr_bits) 600433d6423SLionel Sambuc ++nr_blocks; 601433d6423SLionel Sambuc return(nr_blocks); 602433d6423SLionel Sambuc } 603433d6423SLionel Sambuc 604433d6423SLionel Sambuc /*================================================================ 605433d6423SLionel Sambuc * super - construct a superblock 606433d6423SLionel Sambuc *===============================================================*/ 607433d6423SLionel Sambuc 608433d6423SLionel Sambuc void 609433d6423SLionel Sambuc super(zone_t zones, ino_t inodes) 610433d6423SLionel Sambuc { 611433d6423SLionel Sambuc block_t inodeblks, initblks, i; 612433d6423SLionel Sambuc unsigned long nb; 613433d6423SLionel Sambuc long long ind_per_zone, zo; 614433d6423SLionel Sambuc void *buf; 615433d6423SLionel Sambuc struct super_block *sup; 616433d6423SLionel Sambuc 617433d6423SLionel Sambuc sup = buf = alloc_block(); 618433d6423SLionel Sambuc 619433d6423SLionel Sambuc #ifdef MFSFLAG_CLEAN 620433d6423SLionel Sambuc /* The assumption is that mkfs will create a clean FS. */ 621433d6423SLionel Sambuc sup->s_flags = MFSFLAG_CLEAN; 622433d6423SLionel Sambuc #endif 623433d6423SLionel Sambuc 624433d6423SLionel Sambuc sup->s_ninodes = inodes; 625433d6423SLionel Sambuc /* Check for overflow; cannot happen on V3 file systems */ 626433d6423SLionel Sambuc if(inodes != sup->s_ninodes) 627433d6423SLionel Sambuc errx(1, "Too much inodes for that version of Minix FS."); 628433d6423SLionel Sambuc sup->s_nzones = 0; /* not used in V2 - 0 forces errors early */ 629433d6423SLionel Sambuc sup->s_zones = zones; 630433d6423SLionel Sambuc /* Check for overflow; can only happen on V1 file systems */ 631433d6423SLionel Sambuc if(zones != sup->s_zones) 632433d6423SLionel Sambuc errx(1, "Too much zones (blocks) for that version of Minix FS."); 633433d6423SLionel Sambuc 634433d6423SLionel Sambuc #ifndef MFS_STATIC_BLOCK_SIZE 635433d6423SLionel Sambuc #define BIGGERBLOCKS "Please try a larger block size for an FS of this size." 636433d6423SLionel Sambuc #else 637433d6423SLionel Sambuc #define BIGGERBLOCKS "Please use MinixFS V3 for an FS of this size." 638433d6423SLionel Sambuc #endif 639433d6423SLionel Sambuc sup->s_imap_blocks = nb = bitmapsize(1 + inodes, block_size); 640433d6423SLionel Sambuc /* Checks for an overflow: nb is uint32_t while s_imap_blocks is of type 641433d6423SLionel Sambuc * int16_t */ 642433d6423SLionel Sambuc if(sup->s_imap_blocks != nb) { 643433d6423SLionel Sambuc errx(1, "too many inode bitmap blocks.\n" BIGGERBLOCKS); 644433d6423SLionel Sambuc } 645433d6423SLionel Sambuc sup->s_zmap_blocks = nb = bitmapsize(zones, block_size); 646433d6423SLionel Sambuc /* Idem here check for overflow */ 647433d6423SLionel Sambuc if(nb != sup->s_zmap_blocks) { 648433d6423SLionel Sambuc errx(1, "too many block bitmap blocks.\n" BIGGERBLOCKS); 649433d6423SLionel Sambuc } 650433d6423SLionel Sambuc inode_offset = START_BLOCK + sup->s_imap_blocks + sup->s_zmap_blocks; 651433d6423SLionel Sambuc inodeblks = (inodes + inodes_per_block - 1) / inodes_per_block; 652433d6423SLionel Sambuc initblks = inode_offset + inodeblks; 653433d6423SLionel Sambuc sup->s_firstdatazone_old = nb = 654433d6423SLionel Sambuc (initblks + (1 << zone_shift) - 1) >> zone_shift; 655433d6423SLionel Sambuc if(nb >= zones) errx(1, "bit maps too large"); 656433d6423SLionel Sambuc if(nb != sup->s_firstdatazone_old) { 657433d6423SLionel Sambuc /* The field is too small to store the value. Fortunately, the value 658433d6423SLionel Sambuc * can be computed from other fields. We set the on-disk field to zero 659433d6423SLionel Sambuc * to indicate that it must not be used. Eventually, we can always set 660433d6423SLionel Sambuc * the on-disk field to zero, and stop using it. 661433d6423SLionel Sambuc */ 662433d6423SLionel Sambuc sup->s_firstdatazone_old = 0; 663433d6423SLionel Sambuc } 664433d6423SLionel Sambuc sup->s_firstdatazone = nb; 665433d6423SLionel Sambuc zoff = sup->s_firstdatazone - 1; 666433d6423SLionel Sambuc sup->s_log_zone_size = zone_shift; 667433d6423SLionel Sambuc sup->s_magic = SUPER_MAGIC; 668433d6423SLionel Sambuc #ifdef MFS_SUPER_BLOCK_SIZE 669433d6423SLionel Sambuc sup->s_block_size = block_size; 670433d6423SLionel Sambuc /* Check for overflow */ 671433d6423SLionel Sambuc if(block_size != sup->MFS_SUPER_BLOCK_SIZE) 672433d6423SLionel Sambuc errx(1, "block_size too large."); 673433d6423SLionel Sambuc sup->s_disk_version = 0; 674433d6423SLionel Sambuc #endif 675433d6423SLionel Sambuc 676433d6423SLionel Sambuc ind_per_zone = (long long) indir_per_zone; 677433d6423SLionel Sambuc zo = NR_DZONES + ind_per_zone + ind_per_zone*ind_per_zone; 678433d6423SLionel Sambuc #ifndef MAX_MAX_SIZE 679433d6423SLionel Sambuc #define MAX_MAX_SIZE (INT32_MAX) 680433d6423SLionel Sambuc #endif 681433d6423SLionel Sambuc if(MAX_MAX_SIZE/block_size < zo) { 682433d6423SLionel Sambuc sup->s_max_size = MAX_MAX_SIZE; 683433d6423SLionel Sambuc } 684433d6423SLionel Sambuc else { 685433d6423SLionel Sambuc sup->s_max_size = zo * block_size; 686433d6423SLionel Sambuc } 687433d6423SLionel Sambuc 688433d6423SLionel Sambuc if (verbose>1) { 689433d6423SLionel Sambuc fprintf(stderr, "Super block values:\n" 690433d6423SLionel Sambuc "\tnumber of inodes\t%12d\n" 691433d6423SLionel Sambuc "\tnumber of zones \t%12d\n" 692433d6423SLionel Sambuc "\tinode bit map blocks\t%12d\n" 693433d6423SLionel Sambuc "\tzone bit map blocks\t%12d\n" 694433d6423SLionel Sambuc "\tfirst data zone \t%12d\n" 695433d6423SLionel Sambuc "\tblocks per zone shift\t%12d\n" 696433d6423SLionel Sambuc "\tmaximum file size\t%12d\n" 697433d6423SLionel Sambuc "\tmagic number\t\t%#12X\n", 698433d6423SLionel Sambuc sup->s_ninodes, sup->s_zones, 699433d6423SLionel Sambuc sup->s_imap_blocks, sup->s_zmap_blocks, sup->s_firstdatazone, 700433d6423SLionel Sambuc sup->s_log_zone_size, sup->s_max_size, sup->s_magic); 701433d6423SLionel Sambuc #ifdef MFS_SUPER_BLOCK_SIZE 702433d6423SLionel Sambuc fprintf(stderr, "\tblock size\t\t%12d\n", sup->s_block_size); 703433d6423SLionel Sambuc #endif 704433d6423SLionel Sambuc } 705433d6423SLionel Sambuc 706433d6423SLionel Sambuc mkfs_seek((off_t) SUPER_BLOCK_BYTES, SEEK_SET); 707433d6423SLionel Sambuc mkfs_write(buf, SUPER_BLOCK_BYTES); 708433d6423SLionel Sambuc 709433d6423SLionel Sambuc /* Clear maps and inodes. */ 710433d6423SLionel Sambuc for (i = START_BLOCK; i < initblks; i++) put_block((block_t) i, zero); 711433d6423SLionel Sambuc 712433d6423SLionel Sambuc next_zone = sup->s_firstdatazone; 713433d6423SLionel Sambuc next_inode = 1; 714433d6423SLionel Sambuc 715433d6423SLionel Sambuc zone_map = INODE_MAP + sup->s_imap_blocks; 716433d6423SLionel Sambuc 717433d6423SLionel Sambuc insert_bit(zone_map, 0); /* bit zero must always be allocated */ 718433d6423SLionel Sambuc insert_bit((block_t) INODE_MAP, 0); /* inode zero not used but 719433d6423SLionel Sambuc * must be allocated */ 720433d6423SLionel Sambuc 721433d6423SLionel Sambuc free(buf); 722433d6423SLionel Sambuc } 723433d6423SLionel Sambuc 724433d6423SLionel Sambuc 725433d6423SLionel Sambuc /*================================================================ 726433d6423SLionel Sambuc * rootdir - install the root directory 727433d6423SLionel Sambuc *===============================================================*/ 728433d6423SLionel Sambuc void 729433d6423SLionel Sambuc rootdir(ino_t inode) 730433d6423SLionel Sambuc { 731433d6423SLionel Sambuc zone_t z; 732433d6423SLionel Sambuc 733433d6423SLionel Sambuc z = alloc_zone(); 734433d6423SLionel Sambuc add_zone(inode, z, 2 * sizeof(struct direct), current_time); 735433d6423SLionel Sambuc enter_dir(inode, ".", inode); 736433d6423SLionel Sambuc enter_dir(inode, "..", inode); 737433d6423SLionel Sambuc incr_link(inode); 738433d6423SLionel Sambuc incr_link(inode); 739433d6423SLionel Sambuc } 740433d6423SLionel Sambuc 741433d6423SLionel Sambuc void 742433d6423SLionel Sambuc enter_symlink(ino_t inode, char *lnk) 743433d6423SLionel Sambuc { 744433d6423SLionel Sambuc zone_t z; 745433d6423SLionel Sambuc size_t len; 746433d6423SLionel Sambuc char *buf; 747433d6423SLionel Sambuc 748433d6423SLionel Sambuc buf = alloc_block(); 749433d6423SLionel Sambuc z = alloc_zone(); 750433d6423SLionel Sambuc len = strlen(lnk); 751433d6423SLionel Sambuc if (len >= block_size) 752433d6423SLionel Sambuc pexit("symlink too long, max length is %u", (unsigned)block_size - 1); 753433d6423SLionel Sambuc strcpy(buf, lnk); 754433d6423SLionel Sambuc put_block((z << zone_shift), buf); 755433d6423SLionel Sambuc 756433d6423SLionel Sambuc add_zone(inode, z, len, current_time); 757433d6423SLionel Sambuc 758433d6423SLionel Sambuc free(buf); 759433d6423SLionel Sambuc } 760433d6423SLionel Sambuc 761433d6423SLionel Sambuc 762433d6423SLionel Sambuc /*================================================================ 763433d6423SLionel Sambuc * eat_dir - recursively install directory 764433d6423SLionel Sambuc *===============================================================*/ 765433d6423SLionel Sambuc void 766433d6423SLionel Sambuc eat_dir(ino_t parent) 767433d6423SLionel Sambuc { 768433d6423SLionel Sambuc /* Read prototype lines and set up directory. Recurse if need be. */ 769433d6423SLionel Sambuc char *token[MAX_TOKENS], *p; 770433d6423SLionel Sambuc char line[LINE_LEN]; 771433d6423SLionel Sambuc int mode, usrid, grpid, maj, min, f; 772433d6423SLionel Sambuc ino_t n; 773433d6423SLionel Sambuc zone_t z; 774433d6423SLionel Sambuc size_t size; 775433d6423SLionel Sambuc 776433d6423SLionel Sambuc while (1) { 777433d6423SLionel Sambuc get_line(line, token); 778433d6423SLionel Sambuc p = token[0]; 779433d6423SLionel Sambuc if (*p == '$') return; 780433d6423SLionel Sambuc p = token[1]; 781433d6423SLionel Sambuc mode = mode_con(p); 782433d6423SLionel Sambuc usrid = atoi(token[2]); 783433d6423SLionel Sambuc grpid = atoi(token[3]); 784433d6423SLionel Sambuc n = alloc_inode(mode, usrid, grpid); 785433d6423SLionel Sambuc 786433d6423SLionel Sambuc /* Enter name in directory and update directory's size. */ 787433d6423SLionel Sambuc enter_dir(parent, token[0], n); 788433d6423SLionel Sambuc incr_size(parent, sizeof(struct direct)); 789433d6423SLionel Sambuc 790433d6423SLionel Sambuc /* Check to see if file is directory or special. */ 791433d6423SLionel Sambuc incr_link(n); 792433d6423SLionel Sambuc if (*p == 'd') { 793433d6423SLionel Sambuc /* This is a directory. */ 794433d6423SLionel Sambuc z = alloc_zone(); /* zone for new directory */ 795433d6423SLionel Sambuc add_zone(n, z, 2 * sizeof(struct direct), current_time); 796433d6423SLionel Sambuc enter_dir(n, ".", n); 797433d6423SLionel Sambuc enter_dir(n, "..", parent); 798433d6423SLionel Sambuc incr_link(parent); 799433d6423SLionel Sambuc incr_link(n); 800433d6423SLionel Sambuc eat_dir(n); 801433d6423SLionel Sambuc } else if (*p == 'b' || *p == 'c') { 802433d6423SLionel Sambuc /* Special file. */ 803433d6423SLionel Sambuc maj = atoi(token[4]); 804433d6423SLionel Sambuc min = atoi(token[5]); 805433d6423SLionel Sambuc size = 0; 806433d6423SLionel Sambuc if (token[6]) size = atoi(token[6]); 807433d6423SLionel Sambuc size = block_size * size; 808433d6423SLionel Sambuc add_zone(n, (zone_t) (makedev(maj,min)), size, current_time); 809433d6423SLionel Sambuc } else if (*p == 's') { 810433d6423SLionel Sambuc enter_symlink(n, token[4]); 811433d6423SLionel Sambuc } else { 812433d6423SLionel Sambuc /* Regular file. Go read it. */ 813433d6423SLionel Sambuc if ((f = open(token[4], O_RDONLY)) < 0) { 814cd34841dSBen Gras /* on minix natively, allow EACCES and skip the entry. 815cd34841dSBen Gras * while crossbuilding, always fail on error. 816cd34841dSBen Gras */ 817cd34841dSBen Gras #ifdef __minix 818cd34841dSBen Gras if(errno == EACCES) 819cd34841dSBen Gras warn("Can't open %s", token[4]); 820cd34841dSBen Gras else 821cd34841dSBen Gras #endif 822cd34841dSBen Gras err(1, "Can't open %s", token[4]); 823433d6423SLionel Sambuc } else { 824433d6423SLionel Sambuc eat_file(n, f); 825433d6423SLionel Sambuc } 826433d6423SLionel Sambuc } 827433d6423SLionel Sambuc } 828433d6423SLionel Sambuc 829433d6423SLionel Sambuc } 830433d6423SLionel Sambuc 831433d6423SLionel Sambuc /*================================================================ 832433d6423SLionel Sambuc * eat_file - copy file to MINIX 833433d6423SLionel Sambuc *===============================================================*/ 834433d6423SLionel Sambuc /* Zonesize >= blocksize */ 835433d6423SLionel Sambuc void 836433d6423SLionel Sambuc eat_file(ino_t inode, int f) 837433d6423SLionel Sambuc { 838433d6423SLionel Sambuc int ct = 0, i, j; 839433d6423SLionel Sambuc zone_t z = 0; 840433d6423SLionel Sambuc char *buf; 841433d6423SLionel Sambuc time_t timeval; 842433d6423SLionel Sambuc 843433d6423SLionel Sambuc buf = alloc_block(); 844433d6423SLionel Sambuc 845433d6423SLionel Sambuc do { 846433d6423SLionel Sambuc for (i = 0, j = 0; i < zone_per_block; i++, j += ct) { 847433d6423SLionel Sambuc memset(buf, 0, block_size); 848433d6423SLionel Sambuc if ((ct = read(f, buf, block_size)) > 0) { 849433d6423SLionel Sambuc if (i == 0) z = alloc_zone(); 850433d6423SLionel Sambuc put_block((z << zone_shift) + i, buf); 851433d6423SLionel Sambuc } 852433d6423SLionel Sambuc } 853433d6423SLionel Sambuc timeval = (dflag ? current_time : file_time(f)); 854433d6423SLionel Sambuc if (ct) add_zone(inode, z, (size_t) j, timeval); 855433d6423SLionel Sambuc } while (ct == block_size); 856433d6423SLionel Sambuc close(f); 857433d6423SLionel Sambuc free(buf); 858433d6423SLionel Sambuc } 859433d6423SLionel Sambuc 860433d6423SLionel Sambuc int 861433d6423SLionel Sambuc dir_try_enter(zone_t z, ino_t child, char const *name) 862433d6423SLionel Sambuc { 863433d6423SLionel Sambuc struct direct *dir_entry = alloc_block(); 864433d6423SLionel Sambuc int r = 0; 865433d6423SLionel Sambuc block_t b; 866433d6423SLionel Sambuc int i, l; 867433d6423SLionel Sambuc 868433d6423SLionel Sambuc b = z << zone_shift; 869433d6423SLionel Sambuc for (l = 0; l < zone_per_block; l++, b++) { 870433d6423SLionel Sambuc get_block(b, dir_entry); 871433d6423SLionel Sambuc 872433d6423SLionel Sambuc for (i = 0; i < NR_DIR_ENTRIES(block_size); i++) 873433d6423SLionel Sambuc if (!dir_entry[i].d_ino) 874433d6423SLionel Sambuc break; 875433d6423SLionel Sambuc 876433d6423SLionel Sambuc if(i < NR_DIR_ENTRIES(block_size)) { 877433d6423SLionel Sambuc r = 1; 878433d6423SLionel Sambuc dir_entry[i].d_ino = child; 879433d6423SLionel Sambuc assert(sizeof(dir_entry[i].d_name) == MFS_DIRSIZ); 880433d6423SLionel Sambuc if (verbose && strlen(name) > MFS_DIRSIZ) 881433d6423SLionel Sambuc fprintf(stderr, "File name %s is too long, truncated\n", name); 882433d6423SLionel Sambuc strncpy(dir_entry[i].d_name, name, MFS_DIRSIZ); 883433d6423SLionel Sambuc put_block(b, dir_entry); 884433d6423SLionel Sambuc break; 885433d6423SLionel Sambuc } 886433d6423SLionel Sambuc } 887433d6423SLionel Sambuc 888433d6423SLionel Sambuc free(dir_entry); 889433d6423SLionel Sambuc 890433d6423SLionel Sambuc return r; 891433d6423SLionel Sambuc } 892433d6423SLionel Sambuc 893433d6423SLionel Sambuc /*================================================================ 894433d6423SLionel Sambuc * directory & inode management assist group 895433d6423SLionel Sambuc *===============================================================*/ 896433d6423SLionel Sambuc void 897433d6423SLionel Sambuc enter_dir(ino_t parent, char const *name, ino_t child) 898433d6423SLionel Sambuc { 899433d6423SLionel Sambuc /* Enter child in parent directory */ 900433d6423SLionel Sambuc /* Works for dir > 1 block and zone > block */ 901433d6423SLionel Sambuc unsigned int k; 902433d6423SLionel Sambuc block_t b, indir; 903433d6423SLionel Sambuc zone_t z; 904433d6423SLionel Sambuc int off; 905433d6423SLionel Sambuc struct inode *ino; 906433d6423SLionel Sambuc struct inode *inoblock = alloc_block(); 907433d6423SLionel Sambuc zone_t *indirblock = alloc_block(); 908433d6423SLionel Sambuc 909433d6423SLionel Sambuc assert(!(block_size % sizeof(struct direct))); 910433d6423SLionel Sambuc 911433d6423SLionel Sambuc /* Obtain the inode structure */ 912433d6423SLionel Sambuc b = ((parent - 1) / inodes_per_block) + inode_offset; 913433d6423SLionel Sambuc off = (parent - 1) % inodes_per_block; 914433d6423SLionel Sambuc get_block(b, inoblock); 915433d6423SLionel Sambuc ino = inoblock + off; 916433d6423SLionel Sambuc 917433d6423SLionel Sambuc for (k = 0; k < NR_DZONES; k++) { 918433d6423SLionel Sambuc z = ino->i_zone[k]; 919433d6423SLionel Sambuc if (z == 0) { 920433d6423SLionel Sambuc z = alloc_zone(); 921433d6423SLionel Sambuc ino->i_zone[k] = z; 922433d6423SLionel Sambuc } 923433d6423SLionel Sambuc 924433d6423SLionel Sambuc if(dir_try_enter(z, child, __UNCONST(name))) { 925433d6423SLionel Sambuc put_block(b, inoblock); 926433d6423SLionel Sambuc free(inoblock); 927433d6423SLionel Sambuc free(indirblock); 928433d6423SLionel Sambuc return; 929433d6423SLionel Sambuc } 930433d6423SLionel Sambuc } 931433d6423SLionel Sambuc 932433d6423SLionel Sambuc /* no space in directory using just direct blocks; try indirect */ 933433d6423SLionel Sambuc if (ino->i_zone[S_INDIRECT_IDX] == 0) 934433d6423SLionel Sambuc ino->i_zone[S_INDIRECT_IDX] = alloc_zone(); 935433d6423SLionel Sambuc 936433d6423SLionel Sambuc indir = ino->i_zone[S_INDIRECT_IDX] << zone_shift; 937433d6423SLionel Sambuc --indir; /* Compensate for ++indir below */ 938433d6423SLionel Sambuc for(k = 0; k < (indir_per_zone); k++) { 939433d6423SLionel Sambuc if (k % indir_per_block == 0) 940433d6423SLionel Sambuc get_block(++indir, indirblock); 941433d6423SLionel Sambuc z = indirblock[k % indir_per_block]; 942433d6423SLionel Sambuc if(!z) { 943433d6423SLionel Sambuc z = indirblock[k % indir_per_block] = alloc_zone(); 944433d6423SLionel Sambuc put_block(indir, indirblock); 945433d6423SLionel Sambuc } 946433d6423SLionel Sambuc if(dir_try_enter(z, child, __UNCONST(name))) { 947433d6423SLionel Sambuc put_block(b, inoblock); 948433d6423SLionel Sambuc free(inoblock); 949433d6423SLionel Sambuc free(indirblock); 950433d6423SLionel Sambuc return; 951433d6423SLionel Sambuc } 952433d6423SLionel Sambuc } 953433d6423SLionel Sambuc 954433d6423SLionel Sambuc pexit("Directory-inode %u beyond single indirect blocks. Could not enter %s", 955433d6423SLionel Sambuc (unsigned)parent, name); 956433d6423SLionel Sambuc } 957433d6423SLionel Sambuc 958433d6423SLionel Sambuc 959433d6423SLionel Sambuc void 960433d6423SLionel Sambuc add_zone(ino_t n, zone_t z, size_t bytes, time_t mtime) 961433d6423SLionel Sambuc { 962433d6423SLionel Sambuc /* Add zone z to inode n. The file has grown by 'bytes' bytes. */ 963433d6423SLionel Sambuc 964433d6423SLionel Sambuc int off, i, j; 965433d6423SLionel Sambuc block_t b; 966433d6423SLionel Sambuc zone_t indir, dindir; 967433d6423SLionel Sambuc struct inode *p, *inode; 968433d6423SLionel Sambuc zone_t *blk, *dblk; 969433d6423SLionel Sambuc 970433d6423SLionel Sambuc assert(inodes_per_block*sizeof(*inode) == block_size); 971433d6423SLionel Sambuc if(!(inode = alloc_block())) 972433d6423SLionel Sambuc err(1, "Couldn't allocate block of inodes"); 973433d6423SLionel Sambuc 974433d6423SLionel Sambuc b = ((n - 1) / inodes_per_block) + inode_offset; 975433d6423SLionel Sambuc off = (n - 1) % inodes_per_block; 976433d6423SLionel Sambuc get_block(b, inode); 977433d6423SLionel Sambuc p = &inode[off]; 978433d6423SLionel Sambuc p->i_size += bytes; 979433d6423SLionel Sambuc p->i_mtime = mtime; 980433d6423SLionel Sambuc #ifndef MFS_INODE_ONLY_MTIME /* V1 file systems did not have them... */ 981433d6423SLionel Sambuc p->i_atime = p->i_ctime = current_time; 982433d6423SLionel Sambuc #endif 983433d6423SLionel Sambuc for (i = 0; i < NR_DZONES; i++) 984433d6423SLionel Sambuc if (p->i_zone[i] == 0) { 985433d6423SLionel Sambuc p->i_zone[i] = z; 986433d6423SLionel Sambuc put_block(b, inode); 987433d6423SLionel Sambuc free(inode); 988433d6423SLionel Sambuc return; 989433d6423SLionel Sambuc } 990433d6423SLionel Sambuc 991433d6423SLionel Sambuc assert(indir_per_block*sizeof(*blk) == block_size); 992433d6423SLionel Sambuc if(!(blk = alloc_block())) 993433d6423SLionel Sambuc err(1, "Couldn't allocate indirect block"); 994433d6423SLionel Sambuc 995433d6423SLionel Sambuc /* File has grown beyond a small file. */ 996433d6423SLionel Sambuc if (p->i_zone[S_INDIRECT_IDX] == 0) 997433d6423SLionel Sambuc p->i_zone[S_INDIRECT_IDX] = alloc_zone(); 998433d6423SLionel Sambuc indir = p->i_zone[S_INDIRECT_IDX] << zone_shift; 999433d6423SLionel Sambuc put_block(b, inode); 1000433d6423SLionel Sambuc --indir; /* Compensate for ++indir below */ 1001433d6423SLionel Sambuc for (i = 0; i < (indir_per_zone); i++) { 1002433d6423SLionel Sambuc if (i % indir_per_block == 0) 1003433d6423SLionel Sambuc get_block(++indir, blk); 1004433d6423SLionel Sambuc if (blk[i % indir_per_block] == 0) { 1005433d6423SLionel Sambuc blk[i] = z; 1006433d6423SLionel Sambuc put_block(indir, blk); 1007433d6423SLionel Sambuc free(blk); 1008433d6423SLionel Sambuc free(inode); 1009433d6423SLionel Sambuc return; 1010433d6423SLionel Sambuc } 1011433d6423SLionel Sambuc } 1012433d6423SLionel Sambuc 1013433d6423SLionel Sambuc /* File has grown beyond single indirect; we need a double indirect */ 1014433d6423SLionel Sambuc assert(indir_per_block*sizeof(*dblk) == block_size); 1015433d6423SLionel Sambuc if(!(dblk = alloc_block())) 1016433d6423SLionel Sambuc err(1, "Couldn't allocate double indirect block"); 1017433d6423SLionel Sambuc 1018433d6423SLionel Sambuc if (p->i_zone[D_INDIRECT_IDX] == 0) 1019433d6423SLionel Sambuc p->i_zone[D_INDIRECT_IDX] = alloc_zone(); 1020433d6423SLionel Sambuc dindir = p->i_zone[D_INDIRECT_IDX] << zone_shift; 1021433d6423SLionel Sambuc put_block(b, inode); 1022433d6423SLionel Sambuc --dindir; /* Compensate for ++indir below */ 1023433d6423SLionel Sambuc for (j = 0; j < (indir_per_zone); j++) { 1024433d6423SLionel Sambuc if (j % indir_per_block == 0) 1025433d6423SLionel Sambuc get_block(++dindir, dblk); 1026433d6423SLionel Sambuc if (dblk[j % indir_per_block] == 0) 1027433d6423SLionel Sambuc dblk[j % indir_per_block] = alloc_zone(); 1028433d6423SLionel Sambuc indir = dblk[j % indir_per_block] << zone_shift; 1029433d6423SLionel Sambuc --indir; /* Compensate for ++indir below */ 1030433d6423SLionel Sambuc for (i = 0; i < (indir_per_zone); i++) { 1031433d6423SLionel Sambuc if (i % indir_per_block == 0) 1032433d6423SLionel Sambuc get_block(++indir, blk); 1033433d6423SLionel Sambuc if (blk[i % indir_per_block] == 0) { 1034433d6423SLionel Sambuc blk[i] = z; 1035433d6423SLionel Sambuc put_block(dindir, dblk); 1036433d6423SLionel Sambuc put_block(indir, blk); 1037433d6423SLionel Sambuc free(dblk); 1038433d6423SLionel Sambuc free(blk); 1039433d6423SLionel Sambuc free(inode); 1040433d6423SLionel Sambuc return; 1041433d6423SLionel Sambuc } 1042433d6423SLionel Sambuc } 1043433d6423SLionel Sambuc } 1044433d6423SLionel Sambuc 1045433d6423SLionel Sambuc pexit("File has grown beyond double indirect"); 1046433d6423SLionel Sambuc } 1047433d6423SLionel Sambuc 1048433d6423SLionel Sambuc 1049433d6423SLionel Sambuc /* Increment the link count to inode n */ 1050433d6423SLionel Sambuc void 1051433d6423SLionel Sambuc incr_link(ino_t n) 1052433d6423SLionel Sambuc { 1053433d6423SLionel Sambuc int off; 1054433d6423SLionel Sambuc static int enter = 0; 1055433d6423SLionel Sambuc static struct inode *inodes = NULL; 1056433d6423SLionel Sambuc block_t b; 1057433d6423SLionel Sambuc 1058433d6423SLionel Sambuc if (enter++) pexit("internal error: recursive call to incr_link()"); 1059433d6423SLionel Sambuc 1060433d6423SLionel Sambuc b = ((n - 1) / inodes_per_block) + inode_offset; 1061433d6423SLionel Sambuc off = (n - 1) % inodes_per_block; 1062433d6423SLionel Sambuc { 1063433d6423SLionel Sambuc assert(sizeof(*inodes) * inodes_per_block == block_size); 1064433d6423SLionel Sambuc if(!inodes && !(inodes = alloc_block())) 1065433d6423SLionel Sambuc err(1, "couldn't allocate a block of inodes"); 1066433d6423SLionel Sambuc 1067433d6423SLionel Sambuc get_block(b, inodes); 1068433d6423SLionel Sambuc inodes[off].i_nlinks++; 1069433d6423SLionel Sambuc /* Check overflow (particularly on V1)... */ 1070433d6423SLionel Sambuc if (inodes[off].i_nlinks <= 0) 1071433d6423SLionel Sambuc pexit("Too many links to a directory"); 1072433d6423SLionel Sambuc put_block(b, inodes); 1073433d6423SLionel Sambuc } 1074433d6423SLionel Sambuc enter = 0; 1075433d6423SLionel Sambuc } 1076433d6423SLionel Sambuc 1077433d6423SLionel Sambuc 1078433d6423SLionel Sambuc /* Increment the file-size in inode n */ 1079433d6423SLionel Sambuc void 1080433d6423SLionel Sambuc incr_size(ino_t n, size_t count) 1081433d6423SLionel Sambuc { 1082433d6423SLionel Sambuc block_t b; 1083433d6423SLionel Sambuc int off; 1084433d6423SLionel Sambuc 1085433d6423SLionel Sambuc b = ((n - 1) / inodes_per_block) + inode_offset; 1086433d6423SLionel Sambuc off = (n - 1) % inodes_per_block; 1087433d6423SLionel Sambuc { 1088433d6423SLionel Sambuc struct inode *inodes; 1089433d6423SLionel Sambuc 1090433d6423SLionel Sambuc assert(inodes_per_block * sizeof(*inodes) == block_size); 1091433d6423SLionel Sambuc if(!(inodes = alloc_block())) 1092433d6423SLionel Sambuc err(1, "couldn't allocate a block of inodes"); 1093433d6423SLionel Sambuc 1094433d6423SLionel Sambuc get_block(b, inodes); 1095433d6423SLionel Sambuc /* Check overflow; avoid compiler spurious warnings */ 1096433d6423SLionel Sambuc if (inodes[off].i_size+(int)count < inodes[off].i_size || 1097433d6423SLionel Sambuc inodes[off].i_size > MAX_MAX_SIZE-(int)count) 1098433d6423SLionel Sambuc pexit("File has become too big to be handled by MFS"); 1099433d6423SLionel Sambuc inodes[off].i_size += count; 1100433d6423SLionel Sambuc put_block(b, inodes); 1101433d6423SLionel Sambuc free(inodes); 1102433d6423SLionel Sambuc } 1103433d6423SLionel Sambuc } 1104433d6423SLionel Sambuc 1105433d6423SLionel Sambuc 1106433d6423SLionel Sambuc /*================================================================ 1107433d6423SLionel Sambuc * allocation assist group 1108433d6423SLionel Sambuc *===============================================================*/ 1109433d6423SLionel Sambuc static ino_t 1110433d6423SLionel Sambuc alloc_inode(int mode, int usrid, int grpid) 1111433d6423SLionel Sambuc { 1112433d6423SLionel Sambuc ino_t num; 1113433d6423SLionel Sambuc int off; 1114433d6423SLionel Sambuc block_t b; 1115433d6423SLionel Sambuc struct inode *inodes; 1116433d6423SLionel Sambuc 1117433d6423SLionel Sambuc num = next_inode++; 1118433d6423SLionel Sambuc if (num > nrinodes) { 1119cd34841dSBen Gras pexit("File system does not have enough inodes (only %llu)", nrinodes); 1120433d6423SLionel Sambuc } 1121433d6423SLionel Sambuc b = ((num - 1) / inodes_per_block) + inode_offset; 1122433d6423SLionel Sambuc off = (num - 1) % inodes_per_block; 1123433d6423SLionel Sambuc 1124433d6423SLionel Sambuc assert(inodes_per_block * sizeof(*inodes) == block_size); 1125433d6423SLionel Sambuc if(!(inodes = alloc_block())) 1126433d6423SLionel Sambuc err(1, "couldn't allocate a block of inodes"); 1127433d6423SLionel Sambuc 1128433d6423SLionel Sambuc get_block(b, inodes); 1129433d6423SLionel Sambuc if (inodes[off].i_mode) { 1130cd34841dSBen Gras pexit("allocation new inode %llu with non-zero mode - this cannot happen", 1131433d6423SLionel Sambuc num); 1132433d6423SLionel Sambuc } 1133433d6423SLionel Sambuc inodes[off].i_mode = mode; 1134433d6423SLionel Sambuc inodes[off].i_uid = usrid; 1135433d6423SLionel Sambuc inodes[off].i_gid = grpid; 1136433d6423SLionel Sambuc if (verbose && (inodes[off].i_uid != usrid || inodes[off].i_gid != grpid)) 1137433d6423SLionel Sambuc fprintf(stderr, "Uid/gid %d.%d do not fit within inode, truncated\n", usrid, grpid); 1138433d6423SLionel Sambuc put_block(b, inodes); 1139433d6423SLionel Sambuc 1140433d6423SLionel Sambuc free(inodes); 1141433d6423SLionel Sambuc 1142433d6423SLionel Sambuc /* Set the bit in the bit map. */ 1143433d6423SLionel Sambuc insert_bit((block_t) INODE_MAP, num); 1144433d6423SLionel Sambuc return(num); 1145433d6423SLionel Sambuc } 1146433d6423SLionel Sambuc 1147433d6423SLionel Sambuc 1148433d6423SLionel Sambuc /* Allocate a new zone */ 1149433d6423SLionel Sambuc static zone_t 1150433d6423SLionel Sambuc alloc_zone(void) 1151433d6423SLionel Sambuc { 1152433d6423SLionel Sambuc /* Works for zone > block */ 1153433d6423SLionel Sambuc block_t b; 1154433d6423SLionel Sambuc int i; 1155433d6423SLionel Sambuc zone_t z; 1156433d6423SLionel Sambuc 1157433d6423SLionel Sambuc z = next_zone++; 1158433d6423SLionel Sambuc b = z << zone_shift; 1159433d6423SLionel Sambuc if (b > nrblocks - zone_per_block) 1160433d6423SLionel Sambuc pexit("File system not big enough for all the files"); 1161433d6423SLionel Sambuc for (i = 0; i < zone_per_block; i++) 1162433d6423SLionel Sambuc put_block(b + i, zero); /* give an empty zone */ 1163433d6423SLionel Sambuc 1164433d6423SLionel Sambuc insert_bit(zone_map, z - zoff); 1165433d6423SLionel Sambuc return z; 1166433d6423SLionel Sambuc } 1167433d6423SLionel Sambuc 1168433d6423SLionel Sambuc 1169433d6423SLionel Sambuc /* Insert one bit into the bitmap */ 1170433d6423SLionel Sambuc void 1171433d6423SLionel Sambuc insert_bit(block_t map, bit_t bit) 1172433d6423SLionel Sambuc { 1173433d6423SLionel Sambuc int boff, w, s; 1174433d6423SLionel Sambuc unsigned int bits_per_block; 1175433d6423SLionel Sambuc block_t map_block; 1176433d6423SLionel Sambuc bitchunk_t *buf; 1177433d6423SLionel Sambuc 1178433d6423SLionel Sambuc buf = alloc_block(); 1179433d6423SLionel Sambuc 1180433d6423SLionel Sambuc bits_per_block = FS_BITS_PER_BLOCK(block_size); 1181433d6423SLionel Sambuc map_block = map + bit / bits_per_block; 1182433d6423SLionel Sambuc if (map_block >= inode_offset) 1183433d6423SLionel Sambuc pexit("insertbit invades inodes area - this cannot happen"); 1184433d6423SLionel Sambuc boff = bit % bits_per_block; 1185433d6423SLionel Sambuc 1186433d6423SLionel Sambuc assert(boff >=0); 1187433d6423SLionel Sambuc assert(boff < FS_BITS_PER_BLOCK(block_size)); 1188433d6423SLionel Sambuc get_block(map_block, buf); 1189433d6423SLionel Sambuc w = boff / FS_BITCHUNK_BITS; 1190433d6423SLionel Sambuc s = boff % FS_BITCHUNK_BITS; 1191433d6423SLionel Sambuc buf[w] |= (1 << s); 1192433d6423SLionel Sambuc put_block(map_block, buf); 1193433d6423SLionel Sambuc 1194433d6423SLionel Sambuc free(buf); 1195433d6423SLionel Sambuc } 1196433d6423SLionel Sambuc 1197433d6423SLionel Sambuc 1198433d6423SLionel Sambuc /*================================================================ 1199433d6423SLionel Sambuc * proto-file processing assist group 1200433d6423SLionel Sambuc *===============================================================*/ 1201433d6423SLionel Sambuc int mode_con(char *p) 1202433d6423SLionel Sambuc { 1203433d6423SLionel Sambuc /* Convert string to mode */ 1204433d6423SLionel Sambuc int o1, o2, o3, mode; 1205433d6423SLionel Sambuc char c1, c2, c3; 1206433d6423SLionel Sambuc 1207433d6423SLionel Sambuc c1 = *p++; 1208433d6423SLionel Sambuc c2 = *p++; 1209433d6423SLionel Sambuc c3 = *p++; 1210433d6423SLionel Sambuc o1 = *p++ - '0'; 1211433d6423SLionel Sambuc o2 = *p++ - '0'; 1212433d6423SLionel Sambuc o3 = *p++ - '0'; 1213433d6423SLionel Sambuc mode = (o1 << 6) | (o2 << 3) | o3; 1214433d6423SLionel Sambuc if (c1 == 'd') mode |= S_IFDIR; 1215433d6423SLionel Sambuc if (c1 == 'b') mode |= S_IFBLK; 1216433d6423SLionel Sambuc if (c1 == 'c') mode |= S_IFCHR; 1217433d6423SLionel Sambuc if (c1 == 's') mode |= S_IFLNK; 1218433d6423SLionel Sambuc if (c1 == 'l') mode |= S_IFLNK; /* just to be somewhat ls-compatible*/ 1219433d6423SLionel Sambuc /* XXX note: some other mkfs programs consider L to create hardlinks */ 1220433d6423SLionel Sambuc if (c1 == '-') mode |= S_IFREG; 1221433d6423SLionel Sambuc if (c2 == 'u') mode |= S_ISUID; 1222433d6423SLionel Sambuc if (c3 == 'g') mode |= S_ISGID; 1223433d6423SLionel Sambuc /* XXX There are no way to encode S_ISVTX */ 1224433d6423SLionel Sambuc return(mode); 1225433d6423SLionel Sambuc } 1226433d6423SLionel Sambuc 1227433d6423SLionel Sambuc void 1228433d6423SLionel Sambuc get_line(char line[LINE_LEN], char *parse[MAX_TOKENS]) 1229433d6423SLionel Sambuc { 1230433d6423SLionel Sambuc /* Read a line and break it up in tokens */ 1231433d6423SLionel Sambuc int k; 1232433d6423SLionel Sambuc char c, *p; 1233433d6423SLionel Sambuc int d; 1234433d6423SLionel Sambuc 1235433d6423SLionel Sambuc for (k = 0; k < MAX_TOKENS; k++) parse[k] = 0; 1236433d6423SLionel Sambuc memset(line, 0, LINE_LEN); 1237433d6423SLionel Sambuc k = 0; 1238433d6423SLionel Sambuc p = line; 1239433d6423SLionel Sambuc while (1) { 1240433d6423SLionel Sambuc if (++k > LINE_LEN) pexit("Line too long"); 1241433d6423SLionel Sambuc d = fgetc(proto); 1242433d6423SLionel Sambuc if (d == EOF) pexit("Unexpected end-of-file"); 1243433d6423SLionel Sambuc *p = d; 1244433d6423SLionel Sambuc if (*p == ' ' || *p == '\t') *p = 0; 1245433d6423SLionel Sambuc if (*p == '\n') { 1246433d6423SLionel Sambuc lct++; 1247433d6423SLionel Sambuc *p++ = 0; 1248433d6423SLionel Sambuc *p = '\n'; 1249433d6423SLionel Sambuc break; 1250433d6423SLionel Sambuc } 1251433d6423SLionel Sambuc p++; 1252433d6423SLionel Sambuc } 1253433d6423SLionel Sambuc 1254433d6423SLionel Sambuc k = 0; 1255433d6423SLionel Sambuc p = line; 1256433d6423SLionel Sambuc while (1) { 1257433d6423SLionel Sambuc c = *p++; 1258433d6423SLionel Sambuc if (c == '\n') return; 1259433d6423SLionel Sambuc if (c == 0) continue; 1260433d6423SLionel Sambuc parse[k++] = p - 1; 1261433d6423SLionel Sambuc do { 1262433d6423SLionel Sambuc c = *p++; 1263433d6423SLionel Sambuc } while (c != 0 && c != '\n'); 1264433d6423SLionel Sambuc } 1265433d6423SLionel Sambuc } 1266433d6423SLionel Sambuc 1267433d6423SLionel Sambuc 1268433d6423SLionel Sambuc /*================================================================ 1269433d6423SLionel Sambuc * other stuff 1270433d6423SLionel Sambuc *===============================================================*/ 1271433d6423SLionel Sambuc 1272433d6423SLionel Sambuc /* 1273433d6423SLionel Sambuc * Check to see if the special file named 'device' is mounted. 1274433d6423SLionel Sambuc */ 1275433d6423SLionel Sambuc void 1276433d6423SLionel Sambuc check_mtab(const char *device) /* /dev/hd1 or whatever */ 1277433d6423SLionel Sambuc { 1278433d6423SLionel Sambuc #if defined(__minix) 1279433d6423SLionel Sambuc int n, r; 1280433d6423SLionel Sambuc struct stat sb; 1281433d6423SLionel Sambuc char dev[PATH_MAX], mount_point[PATH_MAX], 1282433d6423SLionel Sambuc type[MNTNAMELEN], flags[MNTFLAGLEN]; 1283433d6423SLionel Sambuc 1284433d6423SLionel Sambuc r= stat(device, &sb); 1285433d6423SLionel Sambuc if (r == -1) 1286433d6423SLionel Sambuc { 1287433d6423SLionel Sambuc if (errno == ENOENT) 1288433d6423SLionel Sambuc return; /* Does not exist, and therefore not mounted. */ 1289433d6423SLionel Sambuc err(1, "stat %s failed", device); 1290433d6423SLionel Sambuc } 1291433d6423SLionel Sambuc if (!S_ISBLK(sb.st_mode)) 1292433d6423SLionel Sambuc { 1293433d6423SLionel Sambuc /* Not a block device and therefore not mounted. */ 1294433d6423SLionel Sambuc return; 1295433d6423SLionel Sambuc } 1296433d6423SLionel Sambuc 1297433d6423SLionel Sambuc if (load_mtab(__UNCONST("mkfs")) < 0) return; 1298433d6423SLionel Sambuc while (1) { 1299433d6423SLionel Sambuc n = get_mtab_entry(dev, mount_point, type, flags); 1300433d6423SLionel Sambuc if (n < 0) return; 1301433d6423SLionel Sambuc if (strcmp(device, dev) == 0) { 1302433d6423SLionel Sambuc /* Can't mkfs on top of a mounted file system. */ 1303433d6423SLionel Sambuc errx(1, "%s is mounted on %s", device, mount_point); 1304433d6423SLionel Sambuc } 1305433d6423SLionel Sambuc } 1306433d6423SLionel Sambuc #else 1307433d6423SLionel Sambuc (void) device; /* shut up warnings about unused variable... */ 1308433d6423SLionel Sambuc #endif 1309433d6423SLionel Sambuc } 1310433d6423SLionel Sambuc 1311433d6423SLionel Sambuc 1312433d6423SLionel Sambuc time_t 1313433d6423SLionel Sambuc file_time(int f) 1314433d6423SLionel Sambuc { 1315433d6423SLionel Sambuc struct stat statbuf; 1316433d6423SLionel Sambuc 1317433d6423SLionel Sambuc if (!fstat(f, &statbuf)) 1318433d6423SLionel Sambuc return current_time; 1319433d6423SLionel Sambuc if (statbuf.st_mtime<0 || statbuf.st_mtime>(uint32_t)(-1)) 1320433d6423SLionel Sambuc return current_time; 1321433d6423SLionel Sambuc return(statbuf.st_mtime); 1322433d6423SLionel Sambuc } 1323433d6423SLionel Sambuc 1324433d6423SLionel Sambuc 1325433d6423SLionel Sambuc __dead void 1326433d6423SLionel Sambuc pexit(char const * s, ...) 1327433d6423SLionel Sambuc { 1328433d6423SLionel Sambuc va_list va; 1329433d6423SLionel Sambuc 1330433d6423SLionel Sambuc va_start(va, s); 1331433d6423SLionel Sambuc vwarn(s, va); 1332433d6423SLionel Sambuc va_end(va); 1333433d6423SLionel Sambuc if (lct != 0) 1334433d6423SLionel Sambuc warnx("Line %d being processed when error detected.\n", lct); 1335433d6423SLionel Sambuc exit(2); 1336433d6423SLionel Sambuc } 1337433d6423SLionel Sambuc 1338433d6423SLionel Sambuc 1339433d6423SLionel Sambuc void * 1340433d6423SLionel Sambuc alloc_block(void) 1341433d6423SLionel Sambuc { 1342433d6423SLionel Sambuc void *buf; 1343433d6423SLionel Sambuc 1344433d6423SLionel Sambuc if(!(buf = malloc(block_size))) { 1345433d6423SLionel Sambuc err(1, "couldn't allocate filesystem buffer"); 1346433d6423SLionel Sambuc } 1347433d6423SLionel Sambuc memset(buf, 0, block_size); 1348433d6423SLionel Sambuc 1349433d6423SLionel Sambuc return buf; 1350433d6423SLionel Sambuc } 1351433d6423SLionel Sambuc 1352433d6423SLionel Sambuc void 1353433d6423SLionel Sambuc print_fs(void) 1354433d6423SLionel Sambuc { 1355433d6423SLionel Sambuc int i, j; 1356433d6423SLionel Sambuc ino_t k; 1357433d6423SLionel Sambuc struct inode *inode2; 1358433d6423SLionel Sambuc unsigned short *usbuf; 1359433d6423SLionel Sambuc block_t b; 1360433d6423SLionel Sambuc struct direct *dir; 1361433d6423SLionel Sambuc 1362433d6423SLionel Sambuc assert(inodes_per_block * sizeof(*inode2) == block_size); 1363433d6423SLionel Sambuc if(!(inode2 = alloc_block())) 1364433d6423SLionel Sambuc err(1, "couldn't allocate a block of inodes"); 1365433d6423SLionel Sambuc 1366433d6423SLionel Sambuc assert(NR_DIR_ENTRIES(block_size)*sizeof(*dir) == block_size); 1367433d6423SLionel Sambuc if(!(dir = alloc_block())) 1368433d6423SLionel Sambuc err(1, "couldn't allocate a block of directory entries"); 1369433d6423SLionel Sambuc 1370433d6423SLionel Sambuc usbuf = alloc_block(); 1371433d6423SLionel Sambuc get_super_block(usbuf); 1372433d6423SLionel Sambuc printf("\nSuperblock: "); 1373433d6423SLionel Sambuc for (i = 0; i < 8; i++) printf("%06ho ", usbuf[i]); 1374433d6423SLionel Sambuc printf("\n "); 1375433d6423SLionel Sambuc for (i = 0; i < 8; i++) printf("%#04hX ", usbuf[i]); 1376433d6423SLionel Sambuc printf("\n "); 1377433d6423SLionel Sambuc for (i = 8; i < 15; i++) printf("%06ho ", usbuf[i]); 1378433d6423SLionel Sambuc printf("\n "); 1379433d6423SLionel Sambuc for (i = 8; i < 15; i++) printf("%#04hX ", usbuf[i]); 1380433d6423SLionel Sambuc get_block((block_t) INODE_MAP, usbuf); 1381433d6423SLionel Sambuc printf("...\nInode map: "); 1382433d6423SLionel Sambuc for (i = 0; i < 9; i++) printf("%06ho ", usbuf[i]); 1383433d6423SLionel Sambuc get_block((block_t) zone_map, usbuf); 1384433d6423SLionel Sambuc printf("...\nZone map: "); 1385433d6423SLionel Sambuc for (i = 0; i < 9; i++) printf("%06ho ", usbuf[i]); 1386433d6423SLionel Sambuc printf("...\n"); 1387433d6423SLionel Sambuc 1388433d6423SLionel Sambuc free(usbuf); 1389433d6423SLionel Sambuc usbuf = NULL; 1390433d6423SLionel Sambuc 1391433d6423SLionel Sambuc k = 0; 1392433d6423SLionel Sambuc for (b = inode_offset; k < nrinodes; b++) { 1393433d6423SLionel Sambuc get_block(b, inode2); 1394433d6423SLionel Sambuc for (i = 0; i < inodes_per_block; i++) { 1395433d6423SLionel Sambuc k = inodes_per_block * (int) (b - inode_offset) + i + 1; 1396433d6423SLionel Sambuc /* Lint but OK */ 1397433d6423SLionel Sambuc if (k > nrinodes) break; 1398433d6423SLionel Sambuc { 1399433d6423SLionel Sambuc if (inode2[i].i_mode != 0) { 1400433d6423SLionel Sambuc printf("Inode %3u: mode=", (unsigned)k); 1401433d6423SLionel Sambuc printf("%06o", (unsigned)inode2[i].i_mode); 1402433d6423SLionel Sambuc printf(" uid=%2d gid=%2d size=", 1403433d6423SLionel Sambuc (int)inode2[i].i_uid, (int)inode2[i].i_gid); 1404433d6423SLionel Sambuc printf("%6ld", (long)inode2[i].i_size); 1405433d6423SLionel Sambuc printf(" zone[0]=%u\n", (unsigned)inode2[i].i_zone[0]); 1406433d6423SLionel Sambuc } 1407433d6423SLionel Sambuc if ((inode2[i].i_mode & S_IFMT) == S_IFDIR) { 1408433d6423SLionel Sambuc /* This is a directory */ 1409433d6423SLionel Sambuc get_block(inode2[i].i_zone[0] << zone_shift, dir); 1410433d6423SLionel Sambuc for (j = 0; j < NR_DIR_ENTRIES(block_size); j++) 1411433d6423SLionel Sambuc if (dir[j].d_ino) 1412433d6423SLionel Sambuc printf("\tInode %2u: %s\n", 1413433d6423SLionel Sambuc (unsigned)dir[j].d_ino, 1414433d6423SLionel Sambuc dir[j].d_name); 1415433d6423SLionel Sambuc } 1416433d6423SLionel Sambuc } 1417433d6423SLionel Sambuc } 1418433d6423SLionel Sambuc } 1419433d6423SLionel Sambuc 1420433d6423SLionel Sambuc if (zone_shift) 1421433d6423SLionel Sambuc printf("%d inodes used. %u zones (%u blocks) used.\n", 1422433d6423SLionel Sambuc (int)next_inode-1, next_zone, next_zone*zone_per_block); 1423433d6423SLionel Sambuc else 1424433d6423SLionel Sambuc printf("%d inodes used. %u zones used.\n", (int)next_inode-1, next_zone); 1425433d6423SLionel Sambuc free(dir); 1426433d6423SLionel Sambuc free(inode2); 1427433d6423SLionel Sambuc } 1428433d6423SLionel Sambuc 1429433d6423SLionel Sambuc 1430433d6423SLionel Sambuc /* 1431433d6423SLionel Sambuc * The first time a block is read, it returns all 0s, unless there has 1432433d6423SLionel Sambuc * been a write. This routine checks to see if a block has been accessed. 1433433d6423SLionel Sambuc */ 1434433d6423SLionel Sambuc int 1435433d6423SLionel Sambuc read_and_set(block_t n) 1436433d6423SLionel Sambuc { 1437433d6423SLionel Sambuc int w, s, mask, r; 1438433d6423SLionel Sambuc 1439433d6423SLionel Sambuc w = n / 8; 1440433d6423SLionel Sambuc 1441433d6423SLionel Sambuc assert(n < nrblocks); 1442433d6423SLionel Sambuc if(w >= umap_array_elements) { 1443433d6423SLionel Sambuc errx(1, "umap array too small - this can't happen"); 1444433d6423SLionel Sambuc } 1445433d6423SLionel Sambuc s = n % 8; 1446433d6423SLionel Sambuc mask = 1 << s; 1447433d6423SLionel Sambuc r = (umap_array[w] & mask ? 1 : 0); 1448433d6423SLionel Sambuc umap_array[w] |= mask; 1449433d6423SLionel Sambuc return(r); 1450433d6423SLionel Sambuc } 1451433d6423SLionel Sambuc 1452433d6423SLionel Sambuc __dead void 1453433d6423SLionel Sambuc usage(void) 1454433d6423SLionel Sambuc { 1455433d6423SLionel Sambuc fprintf(stderr, "Usage: %s [-dltv] [-b blocks] [-i inodes]\n" 1456433d6423SLionel Sambuc "\t[-z zone_shift] [-I offset] [-x extra] [-B blocksize] special [proto]\n", 1457433d6423SLionel Sambuc progname); 1458433d6423SLionel Sambuc exit(4); 1459433d6423SLionel Sambuc } 1460433d6423SLionel Sambuc 1461433d6423SLionel Sambuc void 1462433d6423SLionel Sambuc special(char * string, int insertmode) 1463433d6423SLionel Sambuc { 1464433d6423SLionel Sambuc int openmode = O_RDWR; 1465433d6423SLionel Sambuc if(!insertmode) openmode |= O_TRUNC; 1466433d6423SLionel Sambuc fd = open(string, O_RDWR | O_CREAT, 0644); 1467433d6423SLionel Sambuc if (fd < 0) err(1, "Can't open special file %s", string); 1468433d6423SLionel Sambuc mkfs_seek(0, SEEK_SET); 1469433d6423SLionel Sambuc } 1470433d6423SLionel Sambuc 1471433d6423SLionel Sambuc 1472433d6423SLionel Sambuc 1473433d6423SLionel Sambuc /* Read a block. */ 1474433d6423SLionel Sambuc void 1475433d6423SLionel Sambuc get_block(block_t n, void *buf) 1476433d6423SLionel Sambuc { 1477433d6423SLionel Sambuc ssize_t k; 1478433d6423SLionel Sambuc 1479433d6423SLionel Sambuc /* First access returns a zero block */ 1480433d6423SLionel Sambuc if (read_and_set(n) == 0) { 1481433d6423SLionel Sambuc memcpy(buf, zero, block_size); 1482433d6423SLionel Sambuc return; 1483433d6423SLionel Sambuc } 1484433d6423SLionel Sambuc mkfs_seek((uint64_t)(n) * block_size, SEEK_SET); 1485433d6423SLionel Sambuc k = read(fd, buf, block_size); 1486433d6423SLionel Sambuc if (k != block_size) 1487433d6423SLionel Sambuc pexit("get_block couldn't read block #%u", (unsigned)n); 1488433d6423SLionel Sambuc } 1489433d6423SLionel Sambuc 1490433d6423SLionel Sambuc /* Read the super block. */ 1491433d6423SLionel Sambuc void 1492433d6423SLionel Sambuc get_super_block(void *buf) 1493433d6423SLionel Sambuc { 1494433d6423SLionel Sambuc ssize_t k; 1495433d6423SLionel Sambuc 1496433d6423SLionel Sambuc mkfs_seek((off_t) SUPER_BLOCK_BYTES, SEEK_SET); 1497433d6423SLionel Sambuc k = read(fd, buf, SUPER_BLOCK_BYTES); 1498433d6423SLionel Sambuc if (k != SUPER_BLOCK_BYTES) 1499433d6423SLionel Sambuc err(1, "get_super_block couldn't read super block"); 1500433d6423SLionel Sambuc } 1501433d6423SLionel Sambuc 1502433d6423SLionel Sambuc /* Write a block. */ 1503433d6423SLionel Sambuc void 1504433d6423SLionel Sambuc put_block(block_t n, void *buf) 1505433d6423SLionel Sambuc { 1506433d6423SLionel Sambuc 1507433d6423SLionel Sambuc (void) read_and_set(n); 1508433d6423SLionel Sambuc 1509433d6423SLionel Sambuc mkfs_seek((uint64_t)(n) * block_size, SEEK_SET); 1510433d6423SLionel Sambuc mkfs_write(buf, block_size); 1511433d6423SLionel Sambuc } 1512433d6423SLionel Sambuc 1513433d6423SLionel Sambuc static ssize_t 1514433d6423SLionel Sambuc mkfs_write(void * buf, size_t count) 1515433d6423SLionel Sambuc { 1516433d6423SLionel Sambuc uint64_t fssize; 1517433d6423SLionel Sambuc ssize_t w; 1518433d6423SLionel Sambuc 1519433d6423SLionel Sambuc /* Perform & check write */ 1520433d6423SLionel Sambuc w = write(fd, buf, count); 1521433d6423SLionel Sambuc if(w < 0) 1522433d6423SLionel Sambuc err(1, "mkfs_write: write failed"); 1523433d6423SLionel Sambuc if(w != count) 1524cd34841dSBen Gras errx(1, "mkfs_write: short write: %zd != %zu", w, count); 1525433d6423SLionel Sambuc 1526433d6423SLionel Sambuc /* Check if this has made the FS any bigger; count bytes after offset */ 1527433d6423SLionel Sambuc fssize = mkfs_seek(0, SEEK_CUR); 1528433d6423SLionel Sambuc 1529433d6423SLionel Sambuc assert(fssize >= fs_offset_bytes); 1530433d6423SLionel Sambuc fssize -= fs_offset_bytes; 1531433d6423SLionel Sambuc fssize = roundup(fssize, block_size); 1532433d6423SLionel Sambuc if(fssize > written_fs_size) 1533433d6423SLionel Sambuc written_fs_size = fssize; 1534433d6423SLionel Sambuc 1535433d6423SLionel Sambuc return w; 1536433d6423SLionel Sambuc } 1537433d6423SLionel Sambuc 1538433d6423SLionel Sambuc /* Seek to position in FS we're creating. */ 1539433d6423SLionel Sambuc static uint64_t 1540433d6423SLionel Sambuc mkfs_seek(uint64_t pos, int whence) 1541433d6423SLionel Sambuc { 1542433d6423SLionel Sambuc if(whence == SEEK_SET) pos += fs_offset_bytes; 1543433d6423SLionel Sambuc off_t newpos; 1544433d6423SLionel Sambuc if((newpos=lseek(fd, pos, whence)) == (off_t) -1) 1545433d6423SLionel Sambuc err(1, "mkfs_seek: lseek failed"); 1546433d6423SLionel Sambuc return newpos; 1547433d6423SLionel Sambuc } 1548