1 /* $NetBSD: v7fs_file_util.c,v 1.1 2011/06/27 11:52:24 uch 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 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: v7fs_file_util.c,v 1.1 2011/06/27 11:52:24 uch Exp $"); 34 #ifdef _KERNEL 35 #include <sys/systm.h> 36 #include <sys/param.h> 37 #else 38 #include <stdio.h> 39 #include <string.h> 40 #include <errno.h> 41 #endif 42 43 #include "v7fs.h" 44 #include "v7fs_impl.h" 45 #include "v7fs_endian.h" 46 #include "v7fs_inode.h" 47 #include "v7fs_dirent.h" 48 #include "v7fs_file.h" 49 #include "v7fs_datablock.h" 50 51 #ifdef V7FS_FILE_DEBUG 52 #define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) 53 #else 54 #define DPRINTF(fmt, args...) ((void)0) 55 #endif 56 57 static int replace_subr(struct v7fs_self *, void *, v7fs_daddr_t, size_t); 58 static int lookup_by_number_subr(struct v7fs_self *, void *, v7fs_daddr_t, 59 size_t); 60 61 int 62 v7fs_file_link(struct v7fs_self *fs, struct v7fs_inode *parent_dir, 63 struct v7fs_inode *p, const char *name) 64 { 65 int error = 0; 66 67 DPRINTF("%d %d %s\n", parent_dir->inode_number, p->inode_number, name); 68 if ((error = v7fs_directory_add_entry(fs, parent_dir, p->inode_number, 69 name))) { 70 DPRINTF("can't add entry"); 71 return error; 72 } 73 p->nlink++; 74 v7fs_inode_writeback(fs, p); 75 76 return 0; 77 } 78 79 int 80 v7fs_file_rename(struct v7fs_self *fs, struct v7fs_inode *parent_from, 81 const char *from, struct v7fs_inode *parent_to, const char *to) 82 { 83 v7fs_ino_t from_ino, to_ino; 84 int error; 85 86 if ((error = v7fs_file_lookup_by_name(fs, parent_from, from, 87 &from_ino))) { 88 DPRINTF("%s don't exists\n", from); 89 return error; 90 } 91 92 /* If target file exists, remove. */ 93 error = v7fs_file_lookup_by_name(fs, parent_to, to, &to_ino); 94 if (error == 0) { 95 DPRINTF("%s already exists\n", to); 96 if ((error = v7fs_file_deallocate(fs, parent_to, to))) { 97 DPRINTF("%s can't remove\n", to); 98 return error; 99 } 100 } else if (error != ENOENT) { 101 DPRINTF("error=%d\n", error); 102 return error; 103 } 104 105 if ((error = v7fs_directory_add_entry(fs, parent_to, from_ino, to))) { 106 DPRINTF("can't add entry"); 107 return error; 108 } 109 110 if ((error = v7fs_directory_remove_entry(fs, parent_from, from))) { 111 DPRINTF("can't remove entry"); 112 return error; 113 } 114 115 if (parent_from != parent_to) { 116 /* If directory move, update ".." */ 117 struct v7fs_inode inode; 118 v7fs_inode_load(fs, &inode, from_ino); 119 if (v7fs_inode_isdir(&inode)) { 120 if ((error = v7fs_directory_replace_entry(fs, &inode, 121 "..", parent_to->inode_number))) { 122 DPRINTF("can't replace parent dir"); 123 return error; 124 } 125 v7fs_inode_writeback(fs, &inode); 126 } 127 } 128 129 return 0; 130 } 131 132 133 int 134 v7fs_directory_replace_entry(struct v7fs_self *fs, struct v7fs_inode *self_dir, 135 const char *name, v7fs_ino_t ino) 136 { 137 int error; 138 139 /* Search entry that replaced. replace it to new inode number. */ 140 struct v7fs_lookup_arg lookup_arg = { .name = name, 141 .inode_number = ino }; 142 if ((error = v7fs_datablock_foreach(fs, self_dir, replace_subr, 143 &lookup_arg)) != V7FS_ITERATOR_BREAK) 144 return ENOENT; 145 146 return 0; 147 } 148 149 static int 150 replace_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz) 151 { 152 struct v7fs_lookup_arg *p = (struct v7fs_lookup_arg *)ctx; 153 struct v7fs_dirent *dir; 154 void *buf; 155 size_t i, n; 156 int ret = 0; 157 158 DPRINTF("match start blk=%x\n", blk); 159 if (!(buf = scratch_read(fs, blk))) 160 return EIO; 161 162 dir = (struct v7fs_dirent *)buf; 163 n = sz / sizeof(*dir); 164 165 for (i = 0; i < n; i++, dir++) { /*disk endian */ 166 if (strncmp(p->name, (const char *)dir->name, V7FS_NAME_MAX) 167 == 0) { 168 /* Replace inode# */ 169 dir->inode_number = V7FS_VAL16(fs, p->inode_number); 170 /* Write back. */ 171 if (!fs->io.write(fs->io.cookie, buf, blk)) 172 ret = EIO; 173 else 174 ret = V7FS_ITERATOR_BREAK; 175 break; 176 } 177 } 178 scratch_free(fs, buf); 179 180 return ret; 181 } 182 183 bool 184 v7fs_file_lookup_by_number(struct v7fs_self *fs, struct v7fs_inode *parent_dir, 185 v7fs_ino_t ino, char *buf) 186 { 187 int ret; 188 189 ret = v7fs_datablock_foreach(fs, parent_dir, lookup_by_number_subr, 190 &(struct v7fs_lookup_arg){ .inode_number = ino, .buf = buf }); 191 192 return ret == V7FS_ITERATOR_BREAK; 193 } 194 195 static int 196 lookup_by_number_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, 197 size_t sz) 198 { 199 struct v7fs_lookup_arg *p = (struct v7fs_lookup_arg *)ctx; 200 struct v7fs_dirent *dir; 201 void *buf; 202 size_t i, n; 203 int ret = 0; 204 205 if (!(buf = scratch_read(fs, blk))) 206 return EIO; 207 208 dir = (struct v7fs_dirent *)buf; 209 n = sz / sizeof(*dir); 210 v7fs_dirent_endian_convert(fs, dir, n); 211 212 for (i = 0; i < n; i++, dir++) { 213 if (dir->inode_number == p->inode_number) { 214 if (p->buf) 215 v7fs_dirent_filename(p->buf, dir->name); 216 ret = V7FS_ITERATOR_BREAK; 217 break; 218 } 219 } 220 scratch_free(fs, buf); 221 222 return ret; 223 } 224