1 /* $NetBSD: main.c,v 1.4 2011/07/18 22:50:28 tron Exp $ */ 2 3 /*- 4 * Copyright (c) 2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #if HAVE_NBTOOL_CONFIG_H 33 #include "nbtool_config.h" 34 #endif 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 __RCSID("$NetBSD: main.c,v 1.4 2011/07/18 22:50:28 tron Exp $"); 39 #endif /* not lint */ 40 41 #include <sys/param.h> 42 #include <stdio.h> 43 #include <string.h> 44 #include <errno.h> 45 #include <time.h> 46 #include <err.h> 47 48 #include "v7fs.h" 49 #include "v7fs_impl.h" 50 #include "v7fs_endian.h" 51 #include "v7fs_superblock.h" 52 #include "v7fs_inode.h" 53 #include "v7fs_datablock.h" /*v7fs_datablock_expand/last */ 54 #include "newfs_v7fs.h" 55 #include "progress.h" /*../sbin/fsck */ 56 57 #define VPRINTF(fmt, args...) { if (verbose) printf(fmt, ##args); } 58 59 static v7fs_daddr_t 60 determine_ilist_size(v7fs_daddr_t volume_size, int32_t files) 61 { 62 v7fs_daddr_t ilist_size; 63 64 if (files) 65 ilist_size = (files + V7FS_INODE_PER_BLOCK - 1) / 66 V7FS_INODE_PER_BLOCK; 67 else 68 ilist_size = volume_size / 25; /* 4% */ 69 if (ilist_size > (v7fs_daddr_t)V7FS_ILISTBLK_MAX) 70 ilist_size = V7FS_ILISTBLK_MAX; 71 72 return ilist_size; 73 } 74 75 static int 76 make_root(struct v7fs_self *fs) 77 { 78 struct v7fs_inode inode; 79 struct v7fs_dirent *dir; 80 int error; 81 82 /* INO 1 badblk (don't used) */ 83 memset(&inode, 0, sizeof(inode)); 84 inode.inode_number = 1; 85 inode.mode = V7FS_IFREG; /* V7 manner */ 86 v7fs_inode_writeback(fs, &inode); 87 88 /* INO 2 root */ 89 v7fs_ino_t ino; 90 if ((error = v7fs_inode_allocate(fs, &ino))) { 91 errno = error; 92 warn("Can't allocate / inode"); 93 return error; 94 } 95 96 memset(&inode, 0, sizeof(inode)); 97 inode.inode_number = ino; 98 inode.mode = 0777 | V7FS_IFDIR; 99 inode.uid = 0; 100 inode.gid = 0; 101 inode.nlink = 2; /* . + .. */ 102 inode.atime = inode.mtime = inode.ctime = time(0); 103 104 /* root dirent. */ 105 v7fs_datablock_expand(fs, &inode, sizeof(*dir) * 2); 106 v7fs_daddr_t blk = inode.addr[0]; 107 void *buf; 108 if (!(buf = scratch_read(fs, blk))) { 109 v7fs_inode_deallocate(fs, ino); 110 errno = error = EIO; 111 warn("Can't read / dirent."); 112 return error; 113 } 114 dir = (struct v7fs_dirent *)buf; /*disk endian */ 115 116 strcpy(dir[0].name, "."); 117 dir[0].inode_number = V7FS_VAL16(fs, ino); 118 strcpy(dir[1].name, ".."); 119 dir[1].inode_number = V7FS_VAL16(fs, ino); 120 if (!fs->io.write(fs->io.cookie, buf, blk)) {/*writeback */ 121 scratch_free(fs, buf); 122 errno = error = EIO; 123 warn("Can't write / dirent."); 124 return error; 125 } 126 scratch_free(fs, buf); 127 v7fs_inode_writeback(fs, &inode); 128 if ((error = v7fs_superblock_writeback(fs))) { 129 errno = error; 130 warn("Can't write superblock."); 131 } 132 133 return error; 134 } 135 136 static v7fs_daddr_t 137 make_freeblocklist(struct v7fs_self *fs, v7fs_daddr_t listblk, uint8_t *buf) 138 { 139 uint32_t (*val32)(uint32_t) = fs->val.conv32; 140 uint16_t (*val16)(uint16_t) = fs->val.conv16; 141 struct v7fs_freeblock *fb = (struct v7fs_freeblock *)buf; 142 int i, j, k; 143 144 memset(buf, 0, V7FS_BSIZE); 145 146 for (i = V7FS_MAX_FREEBLOCK - 1, j = listblk + 1, k = 0; i >= 0; 147 i--, j++, k++) { 148 progress(0); 149 if (j == (int32_t)fs->superblock.volume_size) 150 { 151 VPRINTF("\nlast freeblock #%d\n", 152 (*val32)(fb->freeblock[i + 1])); 153 154 memmove(fb->freeblock + 1, fb->freeblock + i + 1, k * 155 sizeof(v7fs_daddr_t)); 156 fb->freeblock[0] = 0; /* Terminate link; */ 157 fb->nfreeblock = (*val16)(k + 1); 158 VPRINTF("last freeblock contains #%d\n", 159 (*val16)(fb->nfreeblock)); 160 fs->io.write(fs->io.cookie, buf, listblk); 161 return 0; 162 } 163 fb->freeblock[i] = (*val32)(j); 164 } 165 fb->nfreeblock = (*val16)(k); 166 167 if (!fs->io.write(fs->io.cookie, buf, listblk)) { 168 errno = EIO; 169 warn("blk=%ld", (long)listblk); 170 return 0; 171 } 172 173 /* Return next link block */ 174 return (*val32)(fb->freeblock[0]); 175 } 176 177 static int 178 make_filesystem(struct v7fs_self *fs, v7fs_daddr_t volume_size, 179 v7fs_daddr_t ilist_size) 180 { 181 struct v7fs_superblock *sb; 182 v7fs_daddr_t blk; 183 uint8_t buf[V7FS_BSIZE]; 184 int error = 0; 185 int32_t i, j; 186 187 /* Setup ilist. (ilist must be zero filled. becuase of they are free) */ 188 VPRINTF("Zero clear ilist.\n"); 189 progress(&(struct progress_arg){ .label = "zero ilist", .tick = 190 ilist_size / PROGRESS_BAR_GRANULE }); 191 memset(buf, 0, sizeof buf); 192 for (i = V7FS_ILIST_SECTOR; i < (int32_t)ilist_size; i++) { 193 fs->io.write(fs->io.cookie, buf, i); 194 progress(0); 195 } 196 progress_done(); 197 VPRINTF("\n"); 198 199 /* Construct superblock */ 200 sb = &fs->superblock; 201 sb->volume_size = volume_size; 202 sb->datablock_start_sector = ilist_size + V7FS_ILIST_SECTOR; 203 sb->update_time = time(NULL); 204 205 /* fill free inode cache. */ 206 VPRINTF("Setup inode cache.\n"); 207 sb->nfreeinode = V7FS_MAX_FREEINODE; 208 for (i = V7FS_MAX_FREEINODE - 1, j = V7FS_ROOT_INODE; i >= 0; i--, j++) 209 sb->freeinode[i] = j; 210 sb->total_freeinode = ilist_size * V7FS_INODE_PER_BLOCK - 1; 211 212 /* fill free block cache. */ 213 VPRINTF("Setup free block cache.\n"); 214 sb->nfreeblock = V7FS_MAX_FREEBLOCK; 215 for (i = V7FS_MAX_FREEBLOCK - 1, j = sb->datablock_start_sector; i >= 0; 216 i--, j++) 217 sb->freeblock[i] = j; 218 219 sb->total_freeblock = volume_size - sb->datablock_start_sector; 220 221 /* Write superblock. */ 222 sb->modified = 1; 223 if ((error = v7fs_superblock_writeback(fs))) { 224 errno = error; 225 warn("Can't write back superblock."); 226 return error; 227 } 228 229 /* Construct freeblock list */ 230 VPRINTF("Setup whole freeblock list.\n"); 231 progress(&(struct progress_arg){ .label = "freeblock list", .tick = 232 (volume_size - sb->datablock_start_sector) / PROGRESS_BAR_GRANULE}); 233 blk = sb->freeblock[0]; 234 while ((blk = make_freeblocklist(fs, blk, buf))) 235 continue; 236 progress_done(); 237 238 VPRINTF("done.\n"); 239 240 return 0; 241 } 242 243 int 244 v7fs_newfs(const struct v7fs_mount_device *mount, int32_t maxfile) 245 { 246 struct v7fs_self *fs; 247 v7fs_daddr_t ilist_size; 248 int error; 249 v7fs_daddr_t volume_size = mount->sectors; 250 251 /* Check and determine ilistblock, datablock size. */ 252 if (volume_size > V7FS_DADDR_MAX + 1) 253 return ENOSPC; 254 255 ilist_size = determine_ilist_size(volume_size, maxfile); 256 257 VPRINTF("volume size=%d, ilist size=%d, endian=%d, NAME_MAX=%d\n", 258 volume_size, ilist_size, mount->endian, V7FS_NAME_MAX); 259 260 /* Setup I/O ops. */ 261 if ((error = v7fs_io_init(&fs, mount, V7FS_BSIZE))) { 262 errno = error; 263 warn("I/O setup failed."); 264 return error; 265 } 266 fs->endian = mount->endian; 267 v7fs_endian_init(fs); 268 269 /* Construct filesystem. */ 270 if ((error = make_filesystem(fs, volume_size, ilist_size))) { 271 return error; 272 } 273 274 /* Setup root. */ 275 if ((error = make_root(fs))) { 276 return error; 277 } 278 279 v7fs_io_fini(fs); 280 281 return 0; 282 } 283