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, ADFS_I(inode)->indaddr, 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 adfs_iterate(struct file *file, struct dir_context *ctx) 239 { 240 struct inode *inode = file_inode(file); 241 struct super_block *sb = inode->i_sb; 242 const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir; 243 struct adfs_dir dir; 244 int ret; 245 246 down_read(&adfs_dir_rwsem); 247 ret = adfs_dir_read_inode(sb, inode, &dir); 248 if (ret) 249 goto unlock; 250 251 if (ctx->pos == 0) { 252 if (!dir_emit_dot(file, ctx)) 253 goto unlock_relse; 254 ctx->pos = 1; 255 } 256 if (ctx->pos == 1) { 257 if (!dir_emit(ctx, "..", 2, dir.parent_id, DT_DIR)) 258 goto unlock_relse; 259 ctx->pos = 2; 260 } 261 262 ret = ops->iterate(&dir, ctx); 263 264 unlock_relse: 265 up_read(&adfs_dir_rwsem); 266 adfs_dir_relse(&dir); 267 return ret; 268 269 unlock: 270 up_read(&adfs_dir_rwsem); 271 return ret; 272 } 273 274 int 275 adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait) 276 { 277 const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir; 278 struct adfs_dir dir; 279 int ret; 280 281 if (!IS_ENABLED(CONFIG_ADFS_FS_RW)) 282 return -EINVAL; 283 284 if (!ops->update) 285 return -EINVAL; 286 287 down_write(&adfs_dir_rwsem); 288 ret = adfs_dir_read(sb, obj->parent_id, 0, &dir); 289 if (ret) 290 goto unlock; 291 292 ret = ops->update(&dir, obj); 293 if (ret) 294 goto forget; 295 296 ret = ops->commit(&dir); 297 if (ret) 298 goto forget; 299 up_write(&adfs_dir_rwsem); 300 301 adfs_dir_mark_dirty(&dir); 302 303 if (wait) 304 ret = adfs_dir_sync(&dir); 305 306 adfs_dir_relse(&dir); 307 return ret; 308 309 /* 310 * If the updated failed because the entry wasn't found, we can 311 * just release the buffers. If it was any other error, forget 312 * the dirtied buffers so they aren't written back to the media. 313 */ 314 forget: 315 if (ret == -ENOENT) 316 adfs_dir_relse(&dir); 317 else 318 adfs_dir_forget(&dir); 319 unlock: 320 up_write(&adfs_dir_rwsem); 321 322 return ret; 323 } 324 325 static unsigned char adfs_tolower(unsigned char c) 326 { 327 if (c >= 'A' && c <= 'Z') 328 c += 'a' - 'A'; 329 return c; 330 } 331 332 static int __adfs_compare(const unsigned char *qstr, u32 qlen, 333 const char *str, u32 len) 334 { 335 u32 i; 336 337 if (qlen != len) 338 return 1; 339 340 for (i = 0; i < qlen; i++) 341 if (adfs_tolower(qstr[i]) != adfs_tolower(str[i])) 342 return 1; 343 344 return 0; 345 } 346 347 static int adfs_dir_lookup_byname(struct inode *inode, const struct qstr *qstr, 348 struct object_info *obj) 349 { 350 struct super_block *sb = inode->i_sb; 351 const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir; 352 const unsigned char *name; 353 struct adfs_dir dir; 354 u32 name_len; 355 int ret; 356 357 down_read(&adfs_dir_rwsem); 358 ret = adfs_dir_read_inode(sb, inode, &dir); 359 if (ret) 360 goto unlock; 361 362 ret = ops->setpos(&dir, 0); 363 if (ret) 364 goto unlock_relse; 365 366 ret = -ENOENT; 367 name = qstr->name; 368 name_len = qstr->len; 369 while (ops->getnext(&dir, obj) == 0) { 370 if (!__adfs_compare(name, name_len, obj->name, obj->name_len)) { 371 ret = 0; 372 break; 373 } 374 } 375 obj->parent_id = ADFS_I(inode)->indaddr; 376 377 unlock_relse: 378 up_read(&adfs_dir_rwsem); 379 adfs_dir_relse(&dir); 380 return ret; 381 382 unlock: 383 up_read(&adfs_dir_rwsem); 384 return ret; 385 } 386 387 const struct file_operations adfs_dir_operations = { 388 .read = generic_read_dir, 389 .llseek = generic_file_llseek, 390 .iterate_shared = adfs_iterate, 391 .fsync = generic_file_fsync, 392 }; 393 394 static int 395 adfs_hash(const struct dentry *parent, struct qstr *qstr) 396 { 397 const unsigned char *name; 398 unsigned long hash; 399 u32 len; 400 401 if (qstr->len > ADFS_SB(parent->d_sb)->s_namelen) 402 return -ENAMETOOLONG; 403 404 len = qstr->len; 405 name = qstr->name; 406 hash = init_name_hash(parent); 407 while (len--) 408 hash = partial_name_hash(adfs_tolower(*name++), hash); 409 qstr->hash = end_name_hash(hash); 410 411 return 0; 412 } 413 414 /* 415 * Compare two names, taking note of the name length 416 * requirements of the underlying filesystem. 417 */ 418 static int adfs_compare(const struct dentry *dentry, unsigned int len, 419 const char *str, const struct qstr *qstr) 420 { 421 return __adfs_compare(qstr->name, qstr->len, str, len); 422 } 423 424 const struct dentry_operations adfs_dentry_operations = { 425 .d_hash = adfs_hash, 426 .d_compare = adfs_compare, 427 }; 428 429 static struct dentry * 430 adfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) 431 { 432 struct inode *inode = NULL; 433 struct object_info obj; 434 int error; 435 436 error = adfs_dir_lookup_byname(dir, &dentry->d_name, &obj); 437 if (error == 0) { 438 /* 439 * This only returns NULL if get_empty_inode 440 * fails. 441 */ 442 inode = adfs_iget(dir->i_sb, &obj); 443 if (!inode) 444 inode = ERR_PTR(-EACCES); 445 } else if (error != -ENOENT) { 446 inode = ERR_PTR(error); 447 } 448 return d_splice_alias(inode, dentry); 449 } 450 451 /* 452 * directories can handle most operations... 453 */ 454 const struct inode_operations adfs_dir_inode_operations = { 455 .lookup = adfs_lookup, 456 .setattr = adfs_notify_change, 457 }; 458