/* * Create new 2.xBSD filesystem. * * Copyright (C) 2006-2014 Serge Vakulenko, * * Permission to use, copy, modify, and distribute this software * and its documentation for any purpose and without fee is hereby * granted, provided that the above copyright notice appear in all * copies and that both that the copyright notice and this * permission notice and warranty disclaimer appear in supporting * documentation, and that the name of the author not be used in * advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * * The author disclaim all warranties with regard to this * software, including all implied warranties of merchantability * and fitness. In no event shall the author be liable for any * special, indirect or consequential damages or any damages * whatsoever resulting from loss of use, data or profits, whether * in an action of contract, negligence or other tortious action, * arising out of or in connection with the use or performance of * this software. */ #include #include #include #include #include #include #include "bsdfs.h" extern int verbose; int inode_build_list (fs_t *fs) { fs_inode_t inode; unsigned int inum, total_inodes; total_inodes = (fs->isize - 1) * BSDFS_INODES_PER_BLOCK; for (inum = 1; inum <= total_inodes; inum++) { if (! fs_inode_get (fs, &inode, inum)) return 0; if (inode.mode == 0) { fs->inode [fs->ninode++] = inum; if (fs->ninode >= NICINOD) break; } } return 1; } static int create_inode1 (fs_t *fs) { fs_inode_t inode; memset (&inode, 0, sizeof(inode)); inode.mode = INODE_MODE_FREG; inode.fs = fs; inode.number = 1; if (! fs_inode_save (&inode, 1)) return 0; fs->tinode--; return 1; } static int create_root_directory (fs_t *fs) { fs_inode_t inode; unsigned char buf [BSDFS_BSIZE]; unsigned int bno; memset (&inode, 0, sizeof(inode)); inode.mode = INODE_MODE_FDIR | 0777; inode.fs = fs; inode.number = BSDFS_ROOT_INODE; inode.size = BSDFS_BSIZE; inode.flags = 0; time (&inode.ctime); time (&inode.atime); time (&inode.mtime); /* directory - put in extra links */ memset (buf, 0, sizeof(buf)); buf[0] = inode.number; buf[1] = inode.number >> 8; buf[2] = inode.number >> 16; buf[3] = inode.number >> 24; buf[4] = 12; buf[5] = 12 >> 8; buf[6] = 1; buf[7] = 1 >> 8; buf[8] = '.'; buf[9] = 0; buf[10] = 0; buf[11] = 0; buf[12+0] = BSDFS_ROOT_INODE; buf[12+1] = BSDFS_ROOT_INODE >> 8; buf[12+2] = BSDFS_ROOT_INODE >> 16; buf[12+3] = BSDFS_ROOT_INODE >> 24; buf[12+4] = 12; buf[12+5] = 12 >> 8; buf[12+6] = 2; buf[12+7] = 2 >> 8; buf[12+8] = '.'; buf[12+9] = '.'; buf[12+10] = 0; buf[12+11] = 0; buf[24+0] = BSDFS_LOSTFOUND_INODE; buf[24+1] = BSDFS_LOSTFOUND_INODE >> 8; buf[24+2] = BSDFS_LOSTFOUND_INODE >> 16; buf[24+3] = BSDFS_LOSTFOUND_INODE >> 24; buf[24+4] = (unsigned char) (BSDFS_BSIZE - 12 - 12); buf[24+5] = (BSDFS_BSIZE - 12 - 12) >> 8; buf[24+6] = 10; buf[24+7] = 10 >> 8; memcpy (&buf[24+8], "lost+found\0\0", 12); if (fs->swapsz != 0) { buf[24+4] = 20; buf[24+5] = 20 >> 8; buf[44+0] = BSDFS_SWAP_INODE; buf[44+1] = BSDFS_SWAP_INODE >> 8; buf[44+2] = BSDFS_SWAP_INODE >> 16; buf[44+3] = BSDFS_SWAP_INODE >> 24; buf[44+4] = (unsigned char) (BSDFS_BSIZE - 12 - 12 - 20); buf[44+5] = (BSDFS_BSIZE - 12 - 12 - 20) >> 8; buf[44+6] = 4; buf[44+7] = 4 >> 8; memcpy (&buf[44+8], "swap\0\0\0\0", 8); } inode.nlink = 3; if (! fs_block_alloc (fs, &bno)) return 0; if (! fs_write_block (fs, bno, buf)) return 0; inode.addr[0] = bno; if (! fs_inode_save (&inode, 1)) return 0; fs->tinode--; return 1; } static int create_lost_found_directory (fs_t *fs) { fs_inode_t inode; unsigned char buf [BSDFS_BSIZE]; unsigned int bno; memset (&inode, 0, sizeof(inode)); inode.mode = INODE_MODE_FDIR | 0777; inode.fs = fs; inode.number = BSDFS_LOSTFOUND_INODE; inode.size = BSDFS_BSIZE; inode.flags = 0; time (&inode.ctime); time (&inode.atime); time (&inode.mtime); /* directory - put in extra links */ memset (buf, 0, sizeof(buf)); buf[0] = inode.number; buf[1] = inode.number >> 8; buf[2] = inode.number >> 16; buf[3] = inode.number >> 24; buf[4] = 12; buf[5] = 12 >> 8; buf[6] = 1; buf[7] = 1 >> 8; buf[8] = '.'; buf[9] = 0; buf[10] = 0; buf[11] = 0; buf[12+0] = BSDFS_ROOT_INODE; buf[12+1] = BSDFS_ROOT_INODE >> 8; buf[12+2] = BSDFS_ROOT_INODE >> 16; buf[12+3] = BSDFS_ROOT_INODE >> 24; buf[12+4] = (unsigned char) (BSDFS_BSIZE - 12); buf[12+5] = (BSDFS_BSIZE - 12) >> 8; buf[12+6] = 2; buf[12+7] = 2 >> 8; buf[12+8] = '.'; buf[12+9] = '.'; buf[12+10] = 0; buf[12+11] = 0; inode.nlink = 2; if (! fs_block_alloc (fs, &bno)) return 0; if (! fs_write_block (fs, bno, buf)) return 0; inode.addr[0] = bno; if (! fs_inode_save (&inode, 1)) return 0; fs->tinode--; return 1; } static void map_block_swap (fs_inode_t *inode, unsigned lbn) { unsigned block [BSDFS_BSIZE / 4]; unsigned int bn, indir, newb, shift, i, j; /* * Blocks 0..NADDR-3 are direct blocks. */ if (lbn < NADDR-3) { /* small file algorithm */ inode->addr[lbn] = inode->fs->isize + lbn; return; } /* * Addresses NADDR-3, NADDR-2, and NADDR-1 * have single, double, triple indirect blocks. * The first step is to determine * how many levels of indirection. */ shift = 0; i = 1; bn = lbn - (NADDR-3); for (j=3; ; j--) { if (j == 0) { fprintf (stderr, "swap: too large size\n"); exit (-1); } shift += NSHIFT; i <<= NSHIFT; if (bn < i) break; bn -= i; } /* * Fetch the first indirect block. */ indir = inode->addr [NADDR-j]; if (indir == 0) { if (! fs_block_alloc (inode->fs, &indir)) { alloc_error: fprintf (stderr, "swap: cannot allocate indirect block\n"); exit (-1); } if (verbose) printf ("swap: allocate indirect block %d (j=%d)\n", indir, j); memset (block, 0, BSDFS_BSIZE); if (! fs_write_block (inode->fs, indir, (unsigned char*) block)) { write_error: fprintf (stderr, "swap: cannot write indirect block %d\n", indir); exit (-1); } inode->addr [NADDR-j] = indir; } /* * Fetch through the indirect blocks */ for (; ; j++) { if (! fs_read_block (inode->fs, indir, (unsigned char*) block)) { fprintf (stderr, "swap: cannot read indirect block %d\n", indir); exit (-1); } shift -= NSHIFT; i = (bn >> shift) & NMASK; if (j == 3) { block[i] = inode->fs->isize + lbn; if (! fs_write_block (inode->fs, indir, (unsigned char*) block)) goto write_error; return; } if (block[i] != 0) { indir = block [i]; continue; } /* Allocate new indirect block. */ if (! fs_block_alloc (inode->fs, &newb)) goto alloc_error; if (verbose) printf ("swap: allocate new block %d (j=%d)\n", newb, j); block[i] = newb; if (! fs_write_block (inode->fs, indir, (unsigned char*) block)) goto write_error; memset (block, 0, BSDFS_BSIZE); if (! fs_write_block (inode->fs, newb, (unsigned char*) block)) { fprintf (stderr, "swap: cannot write block %d\n", newb); exit (-1); } indir = newb; } } static int create_swap_file (fs_t *fs) { fs_inode_t inode; unsigned lbn; memset (&inode, 0, sizeof(inode)); inode.mode = INODE_MODE_FREG | 0400; inode.fs = fs; inode.number = BSDFS_SWAP_INODE; inode.size = fs->swapsz * BSDFS_BSIZE; inode.flags = /*SYS_IMMUTABLE |*/ USER_IMMUTABLE | USER_NODUMP; inode.nlink = 1; inode.dirty = 1; time (&inode.ctime); time (&inode.atime); time (&inode.mtime); for (lbn=0; lbnswapsz; lbn++) map_block_swap (&inode, lbn); if (! fs_inode_save (&inode, 0)) { fprintf (stderr, "swap: cannot save file inode\n"); return 0; } return 1; } int fs_create (fs_t *fs, const char *filename, int kbytes, unsigned swap_kbytes) { int n; unsigned char buf [BSDFS_BSIZE]; off_t bytes, offset; memset (fs, 0, sizeof (*fs)); fs->filename = filename; fs->seek = 0; if (kbytes < 0) { fs->fd = open (fs->filename, O_RDWR); if (fs->fd < 0) return 0; /* Get size and offset from partition table. */ if (! fs_set_partition (fs, -kbytes)) return 0; kbytes = fs->part_nsectors / 2; } else { fs->fd = open (fs->filename, O_CREAT | O_RDWR, 0666); if (fs->fd < 0) return 0; } fs->writable = 1; /* get total disk size * and inode block size */ bytes = (off_t) kbytes * 1024ULL; fs->fsize = bytes / BSDFS_BSIZE; fs->isize = 1 + (fs->fsize / 16 + BSDFS_INODES_PER_BLOCK - 1) / BSDFS_INODES_PER_BLOCK; if (fs->isize < 2) return 0; /* make sure the file is of proper size */ offset = lseek (fs->fd, fs->part_offset + bytes-1, SEEK_SET); if (offset != fs->part_offset + bytes-1) return 0; if (write (fs->fd, "", 1) != 1) { perror ("write"); return 0; } lseek (fs->fd, fs->part_offset, SEEK_SET); /* build a list of free blocks */ fs->swapsz = swap_kbytes * 1024 / BSDFS_BSIZE; fs_block_free (fs, 0); for (n = fs->fsize - 1; n >= fs->isize + fs->swapsz; n--) if (! fs_block_free (fs, n)) return 0; /* initialize inodes */ memset (buf, 0, BSDFS_BSIZE); if (! fs_seek (fs, BSDFS_BSIZE)) return 0; for (n=1; n < fs->isize; n++) { if (! fs_write (fs, buf, BSDFS_BSIZE)) return 0; fs->tinode += BSDFS_INODES_PER_BLOCK; } /* legacy empty inode 1 */ if (! create_inode1 (fs)) return 0; /* lost+found directory */ if (! create_lost_found_directory (fs)) return 0; /* root directory */ if (! create_root_directory (fs)) return 0; /* swap file */ if (fs->swapsz != 0 && ! create_swap_file (fs)) return 0; /* build a list of free inodes */ if (! inode_build_list (fs)) return 0; /* write out super block */ return fs_sync (fs, 1); }