1 1.5 hannken /* $NetBSD: v7fs_file_util.c,v 1.5 2022/02/11 10:55:15 hannken Exp $ */ 2 1.1 uch 3 1.1 uch /*- 4 1.1 uch * Copyright (c) 2011 The NetBSD Foundation, Inc. 5 1.1 uch * All rights reserved. 6 1.1 uch * 7 1.1 uch * This code is derived from software contributed to The NetBSD Foundation 8 1.1 uch * by UCHIYAMA Yasushi. 9 1.1 uch * 10 1.1 uch * Redistribution and use in source and binary forms, with or without 11 1.1 uch * modification, are permitted provided that the following conditions 12 1.1 uch * are met: 13 1.1 uch * 1. Redistributions of source code must retain the above copyright 14 1.1 uch * notice, this list of conditions and the following disclaimer. 15 1.1 uch * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 uch * notice, this list of conditions and the following disclaimer in the 17 1.1 uch * documentation and/or other materials provided with the distribution. 18 1.1 uch * 19 1.1 uch * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 uch * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 uch * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 uch * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 uch * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 uch * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 uch * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 uch * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 uch * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 uch * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 uch * POSSIBILITY OF SUCH DAMAGE. 30 1.1 uch */ 31 1.1 uch 32 1.3 apb #if HAVE_NBTOOL_CONFIG_H 33 1.3 apb #include "nbtool_config.h" 34 1.3 apb #endif 35 1.3 apb 36 1.1 uch #include <sys/cdefs.h> 37 1.5 hannken __KERNEL_RCSID(0, "$NetBSD: v7fs_file_util.c,v 1.5 2022/02/11 10:55:15 hannken Exp $"); 38 1.1 uch #ifdef _KERNEL 39 1.1 uch #include <sys/systm.h> 40 1.1 uch #include <sys/param.h> 41 1.1 uch #else 42 1.1 uch #include <stdio.h> 43 1.1 uch #include <string.h> 44 1.1 uch #include <errno.h> 45 1.1 uch #endif 46 1.1 uch 47 1.1 uch #include "v7fs.h" 48 1.1 uch #include "v7fs_impl.h" 49 1.1 uch #include "v7fs_endian.h" 50 1.1 uch #include "v7fs_inode.h" 51 1.1 uch #include "v7fs_dirent.h" 52 1.1 uch #include "v7fs_file.h" 53 1.1 uch #include "v7fs_datablock.h" 54 1.1 uch 55 1.1 uch #ifdef V7FS_FILE_DEBUG 56 1.1 uch #define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) 57 1.1 uch #else 58 1.1 uch #define DPRINTF(fmt, args...) ((void)0) 59 1.1 uch #endif 60 1.1 uch 61 1.1 uch static int replace_subr(struct v7fs_self *, void *, v7fs_daddr_t, size_t); 62 1.1 uch static int lookup_by_number_subr(struct v7fs_self *, void *, v7fs_daddr_t, 63 1.1 uch size_t); 64 1.4 uch static int can_dirmove(struct v7fs_self *, v7fs_ino_t, v7fs_ino_t); 65 1.4 uch static int lookup_parent_from_dir_subr(struct v7fs_self *, void *, 66 1.4 uch v7fs_daddr_t, size_t); 67 1.1 uch 68 1.1 uch int 69 1.1 uch v7fs_file_link(struct v7fs_self *fs, struct v7fs_inode *parent_dir, 70 1.5 hannken struct v7fs_inode *p, const char *name, size_t namelen) 71 1.1 uch { 72 1.1 uch int error = 0; 73 1.1 uch 74 1.5 hannken DPRINTF("%d %d %.*s\n", parent_dir->inode_number, p->inode_number, 75 1.5 hannken (int)namelen, name); 76 1.1 uch if ((error = v7fs_directory_add_entry(fs, parent_dir, p->inode_number, 77 1.5 hannken name, namelen))) { 78 1.1 uch DPRINTF("can't add entry"); 79 1.1 uch return error; 80 1.1 uch } 81 1.1 uch p->nlink++; 82 1.1 uch v7fs_inode_writeback(fs, p); 83 1.1 uch 84 1.1 uch return 0; 85 1.1 uch } 86 1.1 uch 87 1.1 uch int 88 1.2 uch v7fs_file_symlink(struct v7fs_self *fs, struct v7fs_inode *p, 89 1.2 uch const char *target) 90 1.2 uch { 91 1.2 uch int error; 92 1.2 uch size_t len = strlen(target) + 1; 93 1.2 uch 94 1.2 uch if (len > V7FSBSD_MAXSYMLINKLEN) {/* limited target 512byte pathname */ 95 1.2 uch DPRINTF("too long pathname."); 96 1.2 uch return ENAMETOOLONG; 97 1.2 uch } 98 1.2 uch 99 1.2 uch if ((error = v7fs_datablock_expand(fs, p, len))) { 100 1.2 uch return error; 101 1.2 uch } 102 1.2 uch 103 1.2 uch v7fs_daddr_t blk = p->addr[0]; /* 1block only. */ 104 1.2 uch void *buf; 105 1.2 uch if (!(buf = scratch_read(fs, blk))) { 106 1.2 uch return EIO; 107 1.2 uch } 108 1.2 uch 109 1.2 uch strncpy(buf, target, V7FS_BSIZE); 110 1.2 uch if (!fs->io.write(fs->io.cookie, buf, blk)) { 111 1.2 uch scratch_free(fs, buf); 112 1.2 uch return EIO; 113 1.2 uch } 114 1.2 uch scratch_free(fs, buf); 115 1.2 uch v7fs_inode_writeback(fs, p); 116 1.2 uch 117 1.2 uch return 0; 118 1.2 uch } 119 1.2 uch 120 1.2 uch int 121 1.1 uch v7fs_file_rename(struct v7fs_self *fs, struct v7fs_inode *parent_from, 122 1.5 hannken const char *from, size_t fromlen, struct v7fs_inode *parent_to, 123 1.5 hannken const char *to, size_t tolen) 124 1.1 uch { 125 1.1 uch v7fs_ino_t from_ino, to_ino; 126 1.4 uch struct v7fs_inode inode; 127 1.1 uch int error; 128 1.4 uch bool dir_move; 129 1.1 uch 130 1.4 uch /* Check source file */ 131 1.5 hannken if ((error = v7fs_file_lookup_by_name(fs, parent_from, from, fromlen, 132 1.1 uch &from_ino))) { 133 1.5 hannken DPRINTF("%.*s don't exists\n", (int)fromlen, from); 134 1.1 uch return error; 135 1.1 uch } 136 1.4 uch v7fs_inode_load(fs, &inode, from_ino); 137 1.4 uch dir_move = v7fs_inode_isdir(&inode); 138 1.1 uch 139 1.4 uch /* Check target file */ 140 1.5 hannken error = v7fs_file_lookup_by_name(fs, parent_to, to, tolen, &to_ino); 141 1.4 uch if (error == 0) { /* found */ 142 1.5 hannken DPRINTF("%.*s already exists\n", (int)tolen, to); 143 1.5 hannken if ((error = v7fs_file_deallocate(fs, parent_to, to, tolen))) { 144 1.5 hannken DPRINTF("%.*s can't remove %d\n", (int)tolen, 145 1.5 hannken to, error); 146 1.1 uch return error; 147 1.1 uch } 148 1.1 uch } else if (error != ENOENT) { 149 1.1 uch DPRINTF("error=%d\n", error); 150 1.1 uch return error; 151 1.1 uch } 152 1.4 uch /* Check directory hierarchy. t_vnops rename_dir(5) */ 153 1.4 uch if (dir_move && (error = can_dirmove(fs, from_ino, 154 1.4 uch parent_to->inode_number))) { 155 1.5 hannken DPRINTF("dst '%.*s' is child dir of '%.*s'. error=%d\n", 156 1.5 hannken (int)tolen, to, (int)fromlen, from, error); 157 1.4 uch return error; 158 1.4 uch } 159 1.1 uch 160 1.5 hannken if ((error = v7fs_directory_add_entry(fs, parent_to, from_ino, to, 161 1.5 hannken tolen))) { 162 1.1 uch DPRINTF("can't add entry"); 163 1.1 uch return error; 164 1.1 uch } 165 1.1 uch 166 1.5 hannken if ((error = v7fs_directory_remove_entry(fs, parent_from, from, 167 1.5 hannken fromlen))) { 168 1.1 uch DPRINTF("can't remove entry"); 169 1.1 uch return error; 170 1.1 uch } 171 1.1 uch 172 1.4 uch if (dir_move && (parent_from != parent_to)) { 173 1.1 uch /* If directory move, update ".." */ 174 1.4 uch if ((error = v7fs_directory_replace_entry(fs, &inode, "..", 175 1.4 uch parent_to->inode_number))) { 176 1.4 uch DPRINTF("can't replace parent dir"); 177 1.4 uch return error; 178 1.1 uch } 179 1.4 uch v7fs_inode_writeback(fs, &inode); 180 1.1 uch } 181 1.1 uch 182 1.1 uch return 0; 183 1.1 uch } 184 1.1 uch 185 1.1 uch 186 1.1 uch int 187 1.1 uch v7fs_directory_replace_entry(struct v7fs_self *fs, struct v7fs_inode *self_dir, 188 1.1 uch const char *name, v7fs_ino_t ino) 189 1.1 uch { 190 1.1 uch int error; 191 1.1 uch 192 1.1 uch /* Search entry that replaced. replace it to new inode number. */ 193 1.1 uch struct v7fs_lookup_arg lookup_arg = { .name = name, 194 1.1 uch .inode_number = ino }; 195 1.1 uch if ((error = v7fs_datablock_foreach(fs, self_dir, replace_subr, 196 1.1 uch &lookup_arg)) != V7FS_ITERATOR_BREAK) 197 1.1 uch return ENOENT; 198 1.1 uch 199 1.1 uch return 0; 200 1.1 uch } 201 1.1 uch 202 1.1 uch static int 203 1.1 uch replace_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz) 204 1.1 uch { 205 1.1 uch struct v7fs_lookup_arg *p = (struct v7fs_lookup_arg *)ctx; 206 1.1 uch struct v7fs_dirent *dir; 207 1.1 uch void *buf; 208 1.1 uch size_t i, n; 209 1.1 uch int ret = 0; 210 1.1 uch 211 1.1 uch DPRINTF("match start blk=%x\n", blk); 212 1.1 uch if (!(buf = scratch_read(fs, blk))) 213 1.1 uch return EIO; 214 1.1 uch 215 1.1 uch dir = (struct v7fs_dirent *)buf; 216 1.1 uch n = sz / sizeof(*dir); 217 1.1 uch 218 1.1 uch for (i = 0; i < n; i++, dir++) { /*disk endian */ 219 1.1 uch if (strncmp(p->name, (const char *)dir->name, V7FS_NAME_MAX) 220 1.1 uch == 0) { 221 1.1 uch /* Replace inode# */ 222 1.1 uch dir->inode_number = V7FS_VAL16(fs, p->inode_number); 223 1.1 uch /* Write back. */ 224 1.1 uch if (!fs->io.write(fs->io.cookie, buf, blk)) 225 1.1 uch ret = EIO; 226 1.1 uch else 227 1.1 uch ret = V7FS_ITERATOR_BREAK; 228 1.1 uch break; 229 1.1 uch } 230 1.1 uch } 231 1.1 uch scratch_free(fs, buf); 232 1.1 uch 233 1.1 uch return ret; 234 1.1 uch } 235 1.1 uch 236 1.1 uch bool 237 1.1 uch v7fs_file_lookup_by_number(struct v7fs_self *fs, struct v7fs_inode *parent_dir, 238 1.1 uch v7fs_ino_t ino, char *buf) 239 1.1 uch { 240 1.1 uch int ret; 241 1.1 uch 242 1.1 uch ret = v7fs_datablock_foreach(fs, parent_dir, lookup_by_number_subr, 243 1.1 uch &(struct v7fs_lookup_arg){ .inode_number = ino, .buf = buf }); 244 1.1 uch 245 1.1 uch return ret == V7FS_ITERATOR_BREAK; 246 1.1 uch } 247 1.1 uch 248 1.1 uch static int 249 1.1 uch lookup_by_number_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, 250 1.1 uch size_t sz) 251 1.1 uch { 252 1.1 uch struct v7fs_lookup_arg *p = (struct v7fs_lookup_arg *)ctx; 253 1.1 uch struct v7fs_dirent *dir; 254 1.1 uch void *buf; 255 1.1 uch size_t i, n; 256 1.1 uch int ret = 0; 257 1.1 uch 258 1.1 uch if (!(buf = scratch_read(fs, blk))) 259 1.1 uch return EIO; 260 1.1 uch 261 1.1 uch dir = (struct v7fs_dirent *)buf; 262 1.1 uch n = sz / sizeof(*dir); 263 1.1 uch v7fs_dirent_endian_convert(fs, dir, n); 264 1.1 uch 265 1.1 uch for (i = 0; i < n; i++, dir++) { 266 1.1 uch if (dir->inode_number == p->inode_number) { 267 1.1 uch if (p->buf) 268 1.5 hannken v7fs_dirent_filename(p->buf, dir->name, 269 1.5 hannken strlen(dir->name)); 270 1.1 uch ret = V7FS_ITERATOR_BREAK; 271 1.1 uch break; 272 1.1 uch } 273 1.1 uch } 274 1.1 uch scratch_free(fs, buf); 275 1.1 uch 276 1.1 uch return ret; 277 1.1 uch } 278 1.4 uch 279 1.4 uch struct lookup_parent_arg { 280 1.4 uch v7fs_ino_t parent_ino; 281 1.4 uch }; 282 1.4 uch 283 1.4 uch static int 284 1.4 uch can_dirmove(struct v7fs_self *fs, v7fs_ino_t from_ino, v7fs_ino_t to_ino) 285 1.4 uch { 286 1.4 uch struct v7fs_inode inode; 287 1.4 uch v7fs_ino_t parent; 288 1.4 uch int error; 289 1.4 uch 290 1.4 uch /* Start dir. */ 291 1.4 uch if ((error = v7fs_inode_load(fs, &inode, to_ino))) 292 1.4 uch return error; 293 1.4 uch 294 1.4 uch if (!v7fs_inode_isdir(&inode)) 295 1.4 uch return ENOTDIR; 296 1.4 uch 297 1.4 uch /* Lookup the parent. */ 298 1.4 uch do { 299 1.4 uch struct lookup_parent_arg arg; 300 1.4 uch /* Search parent dir */ 301 1.4 uch arg.parent_ino = 0; 302 1.4 uch v7fs_datablock_foreach(fs, &inode, lookup_parent_from_dir_subr, 303 1.4 uch &arg); 304 1.4 uch if ((parent = arg.parent_ino) == 0) { 305 1.4 uch DPRINTF("***parent missing\n"); 306 1.4 uch return ENOENT; 307 1.4 uch } 308 1.4 uch /* Load parent dir */ 309 1.4 uch if ((error = v7fs_inode_load(fs, &inode, parent))) 310 1.4 uch return error; 311 1.4 uch if (parent == from_ino) { 312 1.4 uch DPRINTF("#%d is child dir of #%d\n", to_ino, from_ino); 313 1.4 uch return EINVAL; 314 1.4 uch } 315 1.4 uch } while (parent != V7FS_ROOT_INODE); 316 1.4 uch 317 1.4 uch return 0; 318 1.4 uch } 319 1.4 uch 320 1.4 uch static int 321 1.4 uch lookup_parent_from_dir_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, 322 1.4 uch size_t sz) 323 1.4 uch { 324 1.4 uch struct lookup_parent_arg *arg = (struct lookup_parent_arg *)ctx; 325 1.4 uch char name[V7FS_NAME_MAX + 1]; 326 1.4 uch void *buf; 327 1.4 uch int ret = 0; 328 1.4 uch 329 1.4 uch if (!(buf = scratch_read(fs, blk))) 330 1.4 uch return 0; 331 1.4 uch struct v7fs_dirent *dir = (struct v7fs_dirent *)buf; 332 1.4 uch size_t i, n = sz / sizeof(*dir); 333 1.4 uch if (!v7fs_dirent_endian_convert(fs, dir, n)) { 334 1.4 uch scratch_free(fs, buf); 335 1.4 uch return V7FS_ITERATOR_ERROR; 336 1.4 uch } 337 1.4 uch 338 1.4 uch for (i = 0; i < n; i++, dir++) { 339 1.5 hannken v7fs_dirent_filename(name, dir->name, strlen(dir->name)); 340 1.4 uch if (strncmp(dir->name, "..", V7FS_NAME_MAX) != 0) 341 1.4 uch continue; 342 1.4 uch 343 1.4 uch arg->parent_ino = dir->inode_number; 344 1.4 uch ret = V7FS_ITERATOR_BREAK; 345 1.4 uch break; 346 1.4 uch } 347 1.4 uch 348 1.4 uch scratch_free(fs, buf); 349 1.4 uch return ret; 350 1.4 uch } 351