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