/* $NetBSD: main.c,v 1.10 2011/08/10 11:31:49 uch Exp $ */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by UCHIYAMA Yasushi. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #if HAVE_NBTOOL_CONFIG_H #include "nbtool_config.h" #endif #include #ifndef lint __RCSID("$NetBSD: main.c,v 1.10 2011/08/10 11:31:49 uch Exp $"); #endif /* not lint */ #include #include #include #include #include #include #include "v7fs.h" #include "v7fs_impl.h" #include "v7fs_endian.h" #include "v7fs_superblock.h" #include "v7fs_inode.h" #include "v7fs_datablock.h" /*v7fs_datablock_expand/last */ #include "newfs_v7fs.h" #include "progress.h" /*../sbin/fsck */ #define VPRINTF(lv, fmt, args...) { if (v7fs_newfs_verbose >= lv) \ printf(fmt, ##args); } static v7fs_daddr_t determine_ilist_size(v7fs_daddr_t volume_size, int32_t files) { v7fs_daddr_t ilist_size; if (files) ilist_size = howmany(files, V7FS_INODE_PER_BLOCK); else ilist_size = volume_size / 25; /* 4% */ if (ilist_size > (v7fs_daddr_t)V7FS_ILISTBLK_MAX) ilist_size = V7FS_ILISTBLK_MAX; return ilist_size; } static int partition_check(struct v7fs_self *fs) { struct v7fs_superblock *sb = &fs->superblock; int error; if ((error = v7fs_superblock_load(fs))) { if (error != EINVAL) { /* Invalid superblock information is OK. */ warnx("Can't read superblock sector."); } } sb->modified = 1; if ((error = v7fs_superblock_writeback(fs))) { if (errno == EROFS) { warnx("Overwriting disk label? "); } warnx("Can't write superblock sector."); } return error; } static int make_root(struct v7fs_self *fs) { struct v7fs_inode inode; struct v7fs_dirent *dir; int error; /* INO 1 badblk (don't used) */ memset(&inode, 0, sizeof(inode)); inode.inode_number = 1; inode.mode = V7FS_IFREG; /* V7 manner */ v7fs_inode_writeback(fs, &inode); /* INO 2 root */ v7fs_ino_t ino; if ((error = v7fs_inode_allocate(fs, &ino))) { errno = error; warn("Can't allocate / inode"); return error; } memset(&inode, 0, sizeof(inode)); inode.inode_number = ino; inode.mode = 0777 | V7FS_IFDIR; inode.uid = 0; inode.gid = 0; inode.nlink = 2; /* . + .. */ inode.atime = inode.mtime = inode.ctime = time(0); /* root dirent. */ v7fs_datablock_expand(fs, &inode, sizeof(*dir) * 2); v7fs_daddr_t blk = inode.addr[0]; void *buf; if (!(buf = scratch_read(fs, blk))) { v7fs_inode_deallocate(fs, ino); errno = error = EIO; warn("Can't read / dirent."); return error; } dir = (struct v7fs_dirent *)buf; /*disk endian */ strcpy(dir[0].name, "."); dir[0].inode_number = V7FS_VAL16(fs, ino); strcpy(dir[1].name, ".."); dir[1].inode_number = V7FS_VAL16(fs, ino); if (!fs->io.write(fs->io.cookie, buf, blk)) {/*writeback */ scratch_free(fs, buf); errno = error = EIO; warn("Can't write / dirent."); return error; } scratch_free(fs, buf); v7fs_inode_writeback(fs, &inode); if ((error = v7fs_superblock_writeback(fs))) { errno = error; warnx("Can't write superblock."); } return error; } static v7fs_daddr_t make_freeblocklist(struct v7fs_self *fs, v7fs_daddr_t listblk, uint8_t *buf) { uint32_t (*val32)(uint32_t) = fs->val.conv32; uint16_t (*val16)(uint16_t) = fs->val.conv16; struct v7fs_freeblock *fb = (struct v7fs_freeblock *)buf; int i, j, k; memset(buf, 0, V7FS_BSIZE); for (i = V7FS_MAX_FREEBLOCK - 1, j = listblk + 1, k = 0; i >= 0; i--, j++, k++) { progress(0); if (j == (int32_t)fs->superblock.volume_size) { VPRINTF(4, "\nlast freeblock #%d\n", (*val32)(fb->freeblock[i + 1])); memmove(fb->freeblock + 1, fb->freeblock + i + 1, k * sizeof(v7fs_daddr_t)); fb->freeblock[0] = 0; /* Terminate link; */ fb->nfreeblock = (*val16)(k + 1); VPRINTF(4, "last freeblock contains #%d\n", (*val16)(fb->nfreeblock)); fs->io.write(fs->io.cookie, buf, listblk); return 0; } fb->freeblock[i] = (*val32)(j); } fb->nfreeblock = (*val16)(k); if (!fs->io.write(fs->io.cookie, buf, listblk)) { errno = EIO; warn("blk=%ld", (long)listblk); return 0; } /* Return next link block */ return (*val32)(fb->freeblock[0]); } static int make_filesystem(struct v7fs_self *fs, v7fs_daddr_t volume_size, v7fs_daddr_t ilist_size) { struct v7fs_superblock *sb; v7fs_daddr_t blk; uint8_t buf[V7FS_BSIZE]; int error = 0; int32_t i, j; /* Setup ilist. (ilist must be zero filled. becuase of they are free) */ VPRINTF(4, "Zero clear ilist.\n"); progress(&(struct progress_arg){ .label = "zero ilist", .tick = ilist_size / PROGRESS_BAR_GRANULE }); memset(buf, 0, sizeof buf); for (i = V7FS_ILIST_SECTOR; i < (int32_t)ilist_size; i++) { fs->io.write(fs->io.cookie, buf, i); progress(0); } #ifndef HAVE_NBTOOL_CONFIG_H progress_done(); #endif VPRINTF(4, "\n"); /* Construct superblock */ sb = &fs->superblock; sb->volume_size = volume_size; sb->datablock_start_sector = ilist_size + V7FS_ILIST_SECTOR; sb->update_time = time(NULL); /* fill free inode cache. */ VPRINTF(4, "Setup inode cache.\n"); sb->nfreeinode = V7FS_MAX_FREEINODE; for (i = V7FS_MAX_FREEINODE - 1, j = V7FS_ROOT_INODE; i >= 0; i--, j++) sb->freeinode[i] = j; sb->total_freeinode = ilist_size * V7FS_INODE_PER_BLOCK - 1; /* fill free block cache. */ VPRINTF(4, "Setup free block cache.\n"); sb->nfreeblock = V7FS_MAX_FREEBLOCK; for (i = V7FS_MAX_FREEBLOCK - 1, j = sb->datablock_start_sector; i >= 0; i--, j++) sb->freeblock[i] = j; sb->total_freeblock = volume_size - sb->datablock_start_sector; /* Write superblock. */ sb->modified = 1; if ((error = v7fs_superblock_writeback(fs))) { errno = error; warn("Can't write back superblock."); return error; } /* Construct freeblock list */ VPRINTF(4, "Setup whole freeblock list.\n"); progress(&(struct progress_arg){ .label = "freeblock list", .tick = (volume_size - sb->datablock_start_sector) / PROGRESS_BAR_GRANULE}); blk = sb->freeblock[0]; while ((blk = make_freeblocklist(fs, blk, buf))) continue; #ifndef HAVE_NBTOOL_CONFIG_H progress_done(); #endif VPRINTF(4, "done.\n"); return 0; } int v7fs_newfs(const struct v7fs_mount_device *mount, int32_t maxfile) { struct v7fs_self *fs; v7fs_daddr_t ilist_size; int error; v7fs_daddr_t volume_size = mount->sectors; /* Check and determine ilistblock, datablock size. */ if (volume_size > V7FS_DADDR_MAX + 1) { warnx("volume size %d over v7fs limit %d. truncated.", volume_size, V7FS_DADDR_MAX + 1); volume_size = V7FS_DADDR_MAX + 1; } ilist_size = determine_ilist_size(volume_size, maxfile); VPRINTF(1, "volume size=%d, ilist size=%d, endian=%d, NAME_MAX=%d\n", volume_size, ilist_size, mount->endian, V7FS_NAME_MAX); /* Setup I/O ops. */ if ((error = v7fs_io_init(&fs, mount, V7FS_BSIZE))) { errno = error; warn("I/O setup failed."); return error; } fs->endian = mount->endian; v7fs_endian_init(fs); if ((error = partition_check(fs))) { return error; } /* Construct filesystem. */ if ((error = make_filesystem(fs, volume_size, ilist_size))) { return error; } /* Setup root. */ if ((error = make_root(fs))) { return error; } v7fs_io_fini(fs); return 0; }