1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * linux/fs/adfs/dir.c 4 * 5 * Copyright (C) 1999-2000 Russell King 6 * 7 * Common directory handling for ADFS 8 */ 9 #include <linux/hex.h> 10 #include <linux/slab.h> 11 #include "adfs.h" 12 13 /* 14 * For future. This should probably be per-directory. 15 */ 16 static DECLARE_RWSEM(adfs_dir_rwsem); 17 18 int adfs_dir_copyfrom(void *dst, struct adfs_dir *dir, unsigned int offset, 19 size_t len) 20 { 21 struct super_block *sb = dir->sb; 22 unsigned int index, remain; 23 24 index = offset >> sb->s_blocksize_bits; 25 offset &= sb->s_blocksize - 1; 26 remain = sb->s_blocksize - offset; 27 if (index + (remain < len) >= dir->nr_buffers) 28 return -EINVAL; 29 30 if (remain < len) { 31 memcpy(dst, dir->bhs[index]->b_data + offset, remain); 32 dst += remain; 33 len -= remain; 34 index += 1; 35 offset = 0; 36 } 37 38 memcpy(dst, dir->bhs[index]->b_data + offset, len); 39 40 return 0; 41 } 42 43 int adfs_dir_copyto(struct adfs_dir *dir, unsigned int offset, const void *src, 44 size_t len) 45 { 46 struct super_block *sb = dir->sb; 47 unsigned int index, remain; 48 49 index = offset >> sb->s_blocksize_bits; 50 offset &= sb->s_blocksize - 1; 51 remain = sb->s_blocksize - offset; 52 if (index + (remain < len) >= dir->nr_buffers) 53 return -EINVAL; 54 55 if (remain < len) { 56 memcpy(dir->bhs[index]->b_data + offset, src, remain); 57 src += remain; 58 len -= remain; 59 index += 1; 60 offset = 0; 61 } 62 63 memcpy(dir->bhs[index]->b_data + offset, src, len); 64 65 return 0; 66 } 67 68 static void __adfs_dir_cleanup(struct adfs_dir *dir) 69 { 70 dir->nr_buffers = 0; 71 72 if (dir->bhs != dir->bh) 73 kfree(dir->bhs); 74 dir->bhs = NULL; 75 dir->sb = NULL; 76 } 77 78 void adfs_dir_relse(struct adfs_dir *dir) 79 { 80 unsigned int i; 81 82 for (i = 0; i < dir->nr_buffers; i++) 83 brelse(dir->bhs[i]); 84 85 __adfs_dir_cleanup(dir); 86 } 87 88 static void adfs_dir_forget(struct adfs_dir *dir) 89 { 90 unsigned int i; 91 92 for (i = 0; i < dir->nr_buffers; i++) 93 bforget(dir->bhs[i]); 94 95 __adfs_dir_cleanup(dir); 96 } 97 98 int adfs_dir_read_buffers(struct super_block *sb, u32 indaddr, 99 unsigned int size, struct adfs_dir *dir) 100 { 101 struct buffer_head **bhs; 102 unsigned int i, num; 103 int block; 104 105 num = ALIGN(size, sb->s_blocksize) >> sb->s_blocksize_bits; 106 if (num > ARRAY_SIZE(dir->bh)) { 107 /* We only allow one extension */ 108 if (dir->bhs != dir->bh) 109 return -EINVAL; 110 111 bhs = kcalloc(num, sizeof(*bhs), GFP_KERNEL); 112 if (!bhs) 113 return -ENOMEM; 114 115 if (dir->nr_buffers) 116 memcpy(bhs, dir->bhs, dir->nr_buffers * sizeof(*bhs)); 117 118 dir->bhs = bhs; 119 } 120 121 for (i = dir->nr_buffers; i < num; i++) { 122 block = __adfs_block_map(sb, indaddr, i); 123 if (!block) { 124 adfs_error(sb, "dir %06x has a hole at offset %u", 125 indaddr, i); 126 goto error; 127 } 128 129 dir->bhs[i] = sb_bread(sb, block); 130 if (!dir->bhs[i]) { 131 adfs_error(sb, 132 "dir %06x failed read at offset %u, mapped block 0x%08x", 133 indaddr, i, block); 134 goto error; 135 } 136 137 dir->nr_buffers++; 138 } 139 return 0; 140 141 error: 142 adfs_dir_relse(dir); 143 144 return -EIO; 145 } 146 147 static int adfs_dir_read(struct super_block *sb, u32 indaddr, 148 unsigned int size, struct adfs_dir *dir) 149 { 150 dir->sb = sb; 151 dir->bhs = dir->bh; 152 dir->nr_buffers = 0; 153 154 return ADFS_SB(sb)->s_dir->read(sb, indaddr, size, dir); 155 } 156 157 static int adfs_dir_read_inode(struct super_block *sb, struct inode *inode, 158 struct adfs_dir *dir) 159 { 160 int ret; 161 162 ret = adfs_dir_read(sb, ADFS_I(inode)->indaddr, inode->i_size, dir); 163 if (ret) 164 return ret; 165 166 if (ADFS_I(inode)->parent_id != dir->parent_id) { 167 adfs_error(sb, 168 "parent directory id changed under me! (%06x but got %06x)\n", 169 ADFS_I(inode)->parent_id, dir->parent_id); 170 adfs_dir_relse(dir); 171 ret = -EIO; 172 } 173 174 return ret; 175 } 176 177 static void adfs_dir_mark_dirty(struct adfs_dir *dir) 178 { 179 unsigned int i; 180 181 /* Mark the buffers dirty */ 182 for (i = 0; i < dir->nr_buffers; i++) 183 mark_buffer_dirty(dir->bhs[i]); 184 } 185 186 static int adfs_dir_sync(struct adfs_dir *dir) 187 { 188 int err = 0; 189 int i; 190 191 for (i = dir->nr_buffers - 1; i >= 0; i--) { 192 struct buffer_head *bh = dir->bhs[i]; 193 sync_dirty_buffer(bh); 194 if (buffer_req(bh) && !buffer_uptodate(bh)) 195 err = -EIO; 196 } 197 198 return err; 199 } 200 201 void adfs_object_fixup(struct adfs_dir *dir, struct object_info *obj) 202 { 203 unsigned int dots, i; 204 205 /* 206 * RISC OS allows the use of '/' in directory entry names, so we need 207 * to fix these up. '/' is typically used for FAT compatibility to 208 * represent '.', so do the same conversion here. In any case, '.' 209 * will never be in a RISC OS name since it is used as the pathname 210 * separator. Handle the case where we may generate a '.' or '..' 211 * name, replacing the first character with '^' (the RISC OS "parent 212 * directory" character.) 213 */ 214 for (i = dots = 0; i < obj->name_len; i++) 215 if (obj->name[i] == '/') { 216 obj->name[i] = '.'; 217 dots++; 218 } 219 220 if (obj->name_len <= 2 && dots == obj->name_len) 221 obj->name[0] = '^'; 222 223 /* 224 * If the object is a file, and the user requested the ,xyz hex 225 * filetype suffix to the name, check the filetype and append. 226 */ 227 if (!(obj->attr & ADFS_NDA_DIRECTORY) && ADFS_SB(dir->sb)->s_ftsuffix) { 228 u16 filetype = adfs_filetype(obj->loadaddr); 229 230 if (filetype != ADFS_FILETYPE_NONE) { 231 obj->name[obj->name_len++] = ','; 232 obj->name[obj->name_len++] = hex_asc_lo(filetype >> 8); 233 obj->name[obj->name_len++] = hex_asc_lo(filetype >> 4); 234 obj->name[obj->name_len++] = hex_asc_lo(filetype >> 0); 235 } 236 } 237 } 238 239 static int adfs_iterate(struct file *file, struct dir_context *ctx) 240 { 241 struct inode *inode = file_inode(file); 242 struct super_block *sb = inode->i_sb; 243 const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir; 244 struct adfs_dir dir; 245 int ret; 246 247 down_read(&adfs_dir_rwsem); 248 ret = adfs_dir_read_inode(sb, inode, &dir); 249 if (ret) 250 goto unlock; 251 252 if (ctx->pos == 0) { 253 if (!dir_emit_dot(file, ctx)) 254 goto unlock_relse; 255 ctx->pos = 1; 256 } 257 if (ctx->pos == 1) { 258 if (!dir_emit(ctx, "..", 2, dir.parent_id, DT_DIR)) 259 goto unlock_relse; 260 ctx->pos = 2; 261 } 262 263 ret = ops->iterate(&dir, ctx); 264 265 unlock_relse: 266 up_read(&adfs_dir_rwsem); 267 adfs_dir_relse(&dir); 268 return ret; 269 270 unlock: 271 up_read(&adfs_dir_rwsem); 272 return ret; 273 } 274 275 int 276 adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait) 277 { 278 const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir; 279 struct adfs_dir dir; 280 int ret; 281 282 if (!IS_ENABLED(CONFIG_ADFS_FS_RW)) 283 return -EINVAL; 284 285 if (!ops->update) 286 return -EINVAL; 287 288 down_write(&adfs_dir_rwsem); 289 ret = adfs_dir_read(sb, obj->parent_id, 0, &dir); 290 if (ret) 291 goto unlock; 292 293 ret = ops->update(&dir, obj); 294 if (ret) 295 goto forget; 296 297 ret = ops->commit(&dir); 298 if (ret) 299 goto forget; 300 up_write(&adfs_dir_rwsem); 301 302 adfs_dir_mark_dirty(&dir); 303 304 if (wait) 305 ret = adfs_dir_sync(&dir); 306 307 adfs_dir_relse(&dir); 308 return ret; 309 310 /* 311 * If the updated failed because the entry wasn't found, we can 312 * just release the buffers. If it was any other error, forget 313 * the dirtied buffers so they aren't written back to the media. 314 */ 315 forget: 316 if (ret == -ENOENT) 317 adfs_dir_relse(&dir); 318 else 319 adfs_dir_forget(&dir); 320 unlock: 321 up_write(&adfs_dir_rwsem); 322 323 return ret; 324 } 325 326 static unsigned char adfs_tolower(unsigned char c) 327 { 328 if (c >= 'A' && c <= 'Z') 329 c += 'a' - 'A'; 330 return c; 331 } 332 333 static int __adfs_compare(const unsigned char *qstr, u32 qlen, 334 const char *str, u32 len) 335 { 336 u32 i; 337 338 if (qlen != len) 339 return 1; 340 341 for (i = 0; i < qlen; i++) 342 if (adfs_tolower(qstr[i]) != adfs_tolower(str[i])) 343 return 1; 344 345 return 0; 346 } 347 348 static int adfs_dir_lookup_byname(struct inode *inode, const struct qstr *qstr, 349 struct object_info *obj) 350 { 351 struct super_block *sb = inode->i_sb; 352 const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir; 353 const unsigned char *name; 354 struct adfs_dir dir; 355 u32 name_len; 356 int ret; 357 358 down_read(&adfs_dir_rwsem); 359 ret = adfs_dir_read_inode(sb, inode, &dir); 360 if (ret) 361 goto unlock; 362 363 ret = ops->setpos(&dir, 0); 364 if (ret) 365 goto unlock_relse; 366 367 ret = -ENOENT; 368 name = qstr->name; 369 name_len = qstr->len; 370 while (ops->getnext(&dir, obj) == 0) { 371 if (!__adfs_compare(name, name_len, obj->name, obj->name_len)) { 372 ret = 0; 373 break; 374 } 375 } 376 obj->parent_id = ADFS_I(inode)->indaddr; 377 378 unlock_relse: 379 up_read(&adfs_dir_rwsem); 380 adfs_dir_relse(&dir); 381 return ret; 382 383 unlock: 384 up_read(&adfs_dir_rwsem); 385 return ret; 386 } 387 388 const struct file_operations adfs_dir_operations = { 389 .read = generic_read_dir, 390 .llseek = generic_file_llseek, 391 .iterate_shared = adfs_iterate, 392 .fsync = generic_file_fsync, 393 }; 394 395 static int 396 adfs_hash(const struct dentry *parent, struct qstr *qstr) 397 { 398 const unsigned char *name; 399 unsigned long hash; 400 u32 len; 401 402 if (qstr->len > ADFS_SB(parent->d_sb)->s_namelen) 403 return -ENAMETOOLONG; 404 405 len = qstr->len; 406 name = qstr->name; 407 hash = init_name_hash(parent); 408 while (len--) 409 hash = partial_name_hash(adfs_tolower(*name++), hash); 410 qstr->hash = end_name_hash(hash); 411 412 return 0; 413 } 414 415 /* 416 * Compare two names, taking note of the name length 417 * requirements of the underlying filesystem. 418 */ 419 static int adfs_compare(const struct dentry *dentry, unsigned int len, 420 const char *str, const struct qstr *qstr) 421 { 422 return __adfs_compare(qstr->name, qstr->len, str, len); 423 } 424 425 const struct dentry_operations adfs_dentry_operations = { 426 .d_hash = adfs_hash, 427 .d_compare = adfs_compare, 428 }; 429 430 static struct dentry * 431 adfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) 432 { 433 struct inode *inode = NULL; 434 struct object_info obj; 435 int error; 436 437 error = adfs_dir_lookup_byname(dir, &dentry->d_name, &obj); 438 if (error == 0) { 439 /* 440 * This only returns NULL if get_empty_inode 441 * fails. 442 */ 443 inode = adfs_iget(dir->i_sb, &obj); 444 if (!inode) 445 inode = ERR_PTR(-EACCES); 446 } else if (error != -ENOENT) { 447 inode = ERR_PTR(error); 448 } 449 return d_splice_alias(inode, dentry); 450 } 451 452 /* 453 * directories can handle most operations... 454 */ 455 const struct inode_operations adfs_dir_inode_operations = { 456 .lookup = adfs_lookup, 457 .setattr = adfs_notify_change, 458 }; 459