1 /* $NetBSD: v7fs_populate.c,v 1.2 2011/07/18 17:15:07 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 #if defined(__RCSID) && !defined(__lint) 38 __RCSID("$NetBSD: v7fs_populate.c,v 1.2 2011/07/18 17:15:07 tron Exp $"); 39 #endif /* !__lint */ 40 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 #include <fcntl.h> 46 #include <errno.h> 47 #include <err.h> 48 49 #if !HAVE_NBTOOL_CONFIG_H 50 #include <sys/mount.h> 51 #endif 52 53 #include "makefs.h" 54 #include "v7fs.h" 55 #include "v7fs_impl.h" 56 #include "v7fs_inode.h" 57 #include "v7fs_superblock.h" 58 #include "v7fs_datablock.h" 59 #include "v7fs_endian.h" 60 #include "v7fs_file.h" 61 #include "v7fs_makefs.h" 62 #include "newfs_v7fs.h" 63 64 extern bool verbose; 65 #define VPRINTF(fmt, args...) { if (verbose) printf(fmt, ##args); } 66 67 static void 68 attr_setup(fsnode *node, struct v7fs_fileattr *attr) 69 { 70 struct stat *st = &node->inode->st; 71 72 attr->mode = node->type | st->st_mode; 73 attr->uid = st->st_uid; 74 attr->gid = st->st_gid; 75 attr->device = 0; 76 attr->ctime = st->st_ctime; 77 attr->atime = st->st_atime; 78 attr->mtime = st->st_mtime; 79 } 80 81 static int 82 allocate(struct v7fs_self *fs, struct v7fs_inode *parent_inode, fsnode *node, 83 dev_t dev, struct v7fs_inode *inode) 84 { 85 int error; 86 v7fs_ino_t ino; 87 struct v7fs_fileattr attr; 88 89 memset(inode, 0, sizeof(*inode)); 90 91 attr_setup(node, &attr); 92 attr.device = dev; 93 if ((error = v7fs_file_allocate(fs, parent_inode, node->name, &attr, 94 &ino))) { 95 errno = error; 96 warn("%s", node->name); 97 return error; 98 } 99 node->inode->ino = ino; 100 node->inode->flags |= FI_ALLOCATED; 101 if ((error = v7fs_inode_load(fs, inode, ino))) { 102 errno = error; 103 warn("%s", node->name); 104 return error; 105 } 106 107 return 0; 108 } 109 110 struct copy_arg { 111 int fd; 112 uint8_t buf[V7FS_BSIZE]; 113 }; 114 115 static int 116 copy_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz) 117 { 118 struct copy_arg *p = ctx; 119 120 if (read(p->fd, p->buf, sz) != (ssize_t)sz) { 121 return V7FS_ITERATOR_ERROR; 122 } 123 124 if (!fs->io.write(fs->io.cookie, p->buf, blk)) { 125 errno = EIO; 126 return V7FS_ITERATOR_ERROR; 127 } 128 progress(0); 129 130 return 0; 131 } 132 133 static int 134 file_copy(struct v7fs_self *fs, struct v7fs_inode *parent_inode, fsnode *node, 135 const char *filepath) 136 { 137 struct v7fs_inode inode; 138 const char *errmsg; 139 fsinode *fnode = node->inode; 140 int error = 0; 141 int fd; 142 143 /* Check hard-link */ 144 if ((fnode->nlink > 1) && (fnode->flags & FI_ALLOCATED)) { 145 if ((error = v7fs_inode_load(fs, &inode, fnode->ino))) { 146 errmsg = "inode load"; 147 goto err_exit; 148 } 149 if ((error = v7fs_file_link(fs, parent_inode, &inode, 150 node->name))) { 151 errmsg = "hard link"; 152 goto err_exit; 153 } 154 return 0; 155 } 156 157 /* Allocate file */ 158 if ((error = allocate(fs, parent_inode, node, 0, &inode))) { 159 errmsg = "file allocate"; 160 goto err_exit; 161 } 162 if ((error = v7fs_datablock_expand(fs, &inode, fnode->st.st_size))) { 163 errmsg = "datablock expand"; 164 goto err_exit; 165 } 166 167 /* Data copy */ 168 if ((fd = open(filepath, O_RDONLY)) == -1) { 169 error = errno; 170 errmsg = "source file"; 171 goto err_exit; 172 } 173 174 error = v7fs_datablock_foreach(fs, &inode, copy_subr, 175 &(struct copy_arg){ .fd = fd }); 176 if (error != V7FS_ITERATOR_END) { 177 errmsg = "data copy"; 178 close(fd); 179 goto err_exit; 180 } else { 181 error = 0; 182 } 183 close(fd); 184 185 return error; 186 187 err_exit: 188 errno = error; 189 warn("%s %s", node->name, errmsg); 190 191 return error; 192 } 193 194 static int 195 populate_walk(struct v7fs_self *fs, struct v7fs_inode *parent_inode, 196 fsnode *root, char *dir) 197 { 198 fsnode *cur; 199 char *mydir = dir + strlen(dir); 200 char srcpath[MAXPATHLEN + 1]; 201 struct v7fs_inode inode; 202 int error = 0; 203 bool failed = false; 204 205 for (cur = root; cur != NULL; cur = cur->next) { 206 switch (cur->type & S_IFMT) { 207 default: 208 VPRINTF("%x\n", cur->flags & S_IFMT); 209 break; 210 case S_IFCHR: 211 /*FALLTHROUGH*/ 212 case S_IFBLK: 213 if ((error = allocate(fs, parent_inode, cur, 214 cur->inode->st.st_rdev, &inode))) { 215 errno = error; 216 warn("%s", cur->name); 217 } 218 break; 219 case S_IFDIR: 220 if (!cur->child) /*'.'*/ 221 break; 222 /* Allocate this directory. */ 223 if ((error = allocate(fs, parent_inode, cur, 0, 224 &inode))) { 225 errno = error; 226 warn("%s", cur->name); 227 } else { 228 /* Populate children. */ 229 mydir[0] = '/'; 230 strcpy(&mydir[1], cur->name); 231 error = populate_walk(fs, &inode, cur->child, 232 dir); 233 mydir[0] = '\0'; 234 } 235 break; 236 case S_IFREG: 237 snprintf(srcpath, sizeof(srcpath), "%s/%s", dir, 238 cur->name); 239 error = file_copy(fs, parent_inode, cur, srcpath); 240 break; 241 case S_IFLNK: 242 if ((error = allocate(fs, parent_inode, cur, 0, 243 &inode))) { 244 errno = error; 245 warn("%s", cur->name); 246 } else { 247 v7fs_file_symlink(fs, &inode, cur->symlink); 248 } 249 break; 250 } 251 if (error) 252 failed = true; 253 } 254 255 return failed ? 2 : 0; 256 } 257 258 int 259 v7fs_populate(const char *dir, fsnode *root, fsinfo_t *fsopts, 260 const struct v7fs_mount_device *device) 261 { 262 v7fs_opt_t *v7fs_opts = fsopts->fs_specific; 263 static char path[MAXPATHLEN + 1]; 264 struct v7fs_inode root_inode; 265 struct v7fs_self *fs; 266 int error; 267 268 if ((error = v7fs_io_init(&fs, device, V7FS_BSIZE))) { 269 errno = error; 270 warn("I/O setup failed."); 271 return error; 272 } 273 fs->endian = device->endian; 274 v7fs_endian_init(fs); 275 276 if ((error = v7fs_superblock_load(fs))) { 277 errno = error; 278 warn("Can't load superblock."); 279 return error; 280 } 281 fsopts->superblock = &fs->superblock; /* not used. */ 282 283 if ((error = v7fs_inode_load(fs, &root_inode, V7FS_ROOT_INODE))) { 284 errno = error; 285 warn("Can't load root inode."); 286 return error; 287 } 288 289 progress(&(struct progress_arg){ .label = "populate", .tick = 290 v7fs_opts->npuredatablk / PROGRESS_BAR_GRANULE }); 291 292 strncpy(path, dir, sizeof(path)); 293 error = populate_walk(fs, &root_inode, root, path); 294 295 v7fs_inode_writeback(fs, &root_inode); 296 v7fs_superblock_writeback(fs); 297 298 return error; 299 } 300