d2912cb15bdda (Thomas Gleixner 2019-06-04 10:11:33 +0200 1) // SPDX-License-Identifier: GPL-2.0-only
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 3) * linux/fs/adfs/dir_fplus.c
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 4) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 5) * Copyright (C) 1997-1999 Russell King
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 6) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 7) #include "adfs.h"
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 8) #include "dir_fplus.h"
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 9)
0db35a02a1c3f (Russell King 2019-12-09 11:10:52 +0000 10) /* Return the byte offset to directory entry pos */
0db35a02a1c3f (Russell King 2019-12-09 11:10:52 +0000 11) static unsigned int adfs_fplus_offset(const struct adfs_bigdirheader *h,
0db35a02a1c3f (Russell King 2019-12-09 11:10:52 +0000 12) unsigned int pos)
0db35a02a1c3f (Russell King 2019-12-09 11:10:52 +0000 13) {
0db35a02a1c3f (Russell King 2019-12-09 11:10:52 +0000 14) return offsetof(struct adfs_bigdirheader, bigdirname) +
0db35a02a1c3f (Russell King 2019-12-09 11:10:52 +0000 15) ALIGN(le32_to_cpu(h->bigdirnamelen), 4) +
0db35a02a1c3f (Russell King 2019-12-09 11:10:52 +0000 16) pos * sizeof(struct adfs_bigdirentry);
0db35a02a1c3f (Russell King 2019-12-09 11:10:52 +0000 17) }
0db35a02a1c3f (Russell King 2019-12-09 11:10:52 +0000 18)
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 19) static int adfs_fplus_validate_header(const struct adfs_bigdirheader *h)
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 20) {
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 21) unsigned int size = le32_to_cpu(h->bigdirsize);
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 22) unsigned int len;
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 23)
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 24) if (h->bigdirversion[0] != 0 || h->bigdirversion[1] != 0 ||
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 25) h->bigdirversion[2] != 0 ||
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 26) h->bigdirstartname != cpu_to_le32(BIGDIRSTARTNAME) ||
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 27) !size || size & 2047 || size > SZ_4M)
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 28) return -EIO;
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 29)
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 30) size -= sizeof(struct adfs_bigdirtail) +
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 31) offsetof(struct adfs_bigdirheader, bigdirname);
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 32)
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 33) /* Check that bigdirnamelen fits within the directory */
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 34) len = ALIGN(le32_to_cpu(h->bigdirnamelen), 4);
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 35) if (len > size)
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 36) return -EIO;
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 37)
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 38) size -= len;
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 39)
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 40) /* Check that bigdirnamesize fits within the directory */
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 41) len = le32_to_cpu(h->bigdirnamesize);
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 42) if (len > size)
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 43) return -EIO;
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 44)
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 45) size -= len;
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 46)
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 47) /*
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 48) * Avoid division, we know that absolute maximum number of entries
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 49) * can not be so large to cause overflow of the multiplication below.
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 50) */
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 51) len = le32_to_cpu(h->bigdirentries);
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 52) if (len > SZ_4M / sizeof(struct adfs_bigdirentry) ||
aa3d4e015298f (Russell King 2019-12-09 11:11:02 +0000 53) len * sizeof(struct adfs_bigdirentry) > size)
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 54) return -EIO;
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 55)
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 56) return 0;
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 57) }
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 58)
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 59) static int adfs_fplus_validate_tail(const struct adfs_bigdirheader *h,
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 60) const struct adfs_bigdirtail *t)
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 61) {
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 62) if (t->bigdirendname != cpu_to_le32(BIGDIRENDNAME) ||
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 63) t->bigdirendmasseq != h->startmasseq ||
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 64) t->reserved[0] != 0 || t->reserved[1] != 0)
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 65) return -EIO;
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 66)
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 67) return 0;
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 68) }
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 69)
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 70) static u8 adfs_fplus_checkbyte(struct adfs_dir *dir)
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 71) {
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 72) struct adfs_bigdirheader *h = dir->bighead;
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 73) struct adfs_bigdirtail *t = dir->bigtail;
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 74) unsigned int end, bs, bi, i;
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 75) __le32 *bp;
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 76) u32 dircheck;
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 77)
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 78) end = adfs_fplus_offset(h, le32_to_cpu(h->bigdirentries)) +
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 79) le32_to_cpu(h->bigdirnamesize);
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 80)
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 81) /* Accumulate the contents of the header, entries and names */
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 82) for (dircheck = 0, bi = 0; end; bi++) {
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 83) bp = (void *)dir->bhs[bi]->b_data;
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 84) bs = dir->bhs[bi]->b_size;
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 85) if (bs > end)
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 86) bs = end;
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 87)
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 88) for (i = 0; i < bs; i += sizeof(u32))
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 89) dircheck = ror32(dircheck, 13) ^ le32_to_cpup(bp++);
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 90)
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 91) end -= bs;
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 92) }
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 93)
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 94) /* Accumulate the contents of the tail except for the check byte */
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 95) dircheck = ror32(dircheck, 13) ^ le32_to_cpu(t->bigdirendname);
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 96) dircheck = ror32(dircheck, 13) ^ t->bigdirendmasseq;
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 97) dircheck = ror32(dircheck, 13) ^ t->reserved[0];
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 98) dircheck = ror32(dircheck, 13) ^ t->reserved[1];
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 99)
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 100) return dircheck ^ dircheck >> 8 ^ dircheck >> 16 ^ dircheck >> 24;
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 101) }
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 102)
419a6e5e82ca0 (Russell King 2019-12-09 11:09:35 +0000 103) static int adfs_fplus_read(struct super_block *sb, u32 indaddr,
419a6e5e82ca0 (Russell King 2019-12-09 11:09:35 +0000 104) unsigned int size, struct adfs_dir *dir)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 105) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 106) struct adfs_bigdirheader *h;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 107) struct adfs_bigdirtail *t;
419a6e5e82ca0 (Russell King 2019-12-09 11:09:35 +0000 108) unsigned int dirsize;
419a6e5e82ca0 (Russell King 2019-12-09 11:09:35 +0000 109) int ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 110)
419a6e5e82ca0 (Russell King 2019-12-09 11:09:35 +0000 111) /* Read first buffer */
419a6e5e82ca0 (Russell King 2019-12-09 11:09:35 +0000 112) ret = adfs_dir_read_buffers(sb, indaddr, sb->s_blocksize, dir);
419a6e5e82ca0 (Russell King 2019-12-09 11:09:35 +0000 113) if (ret)
419a6e5e82ca0 (Russell King 2019-12-09 11:09:35 +0000 114) return ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 115)
016936b32131d (Russell King 2019-12-09 11:10:21 +0000 116) dir->bighead = h = (void *)dir->bhs[0]->b_data;
587065dcac64e (Dan Carpenter 2020-01-24 13:15:37 +0300 117) ret = adfs_fplus_validate_header(h);
587065dcac64e (Dan Carpenter 2020-01-24 13:15:37 +0300 118) if (ret) {
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 119) adfs_error(sb, "dir %06x has malformed header", indaddr);
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 120) goto out;
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 121) }
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 122)
419a6e5e82ca0 (Russell King 2019-12-09 11:09:35 +0000 123) dirsize = le32_to_cpu(h->bigdirsize);
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 124) if (size && dirsize != size) {
ceb3b10613eba (Russell King 2019-06-04 14:49:52 +0100 125) adfs_msg(sb, KERN_WARNING,
419a6e5e82ca0 (Russell King 2019-12-09 11:09:35 +0000 126) "dir %06x header size %X does not match directory size %X",
419a6e5e82ca0 (Russell King 2019-12-09 11:09:35 +0000 127) indaddr, dirsize, size);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 128) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 129)
419a6e5e82ca0 (Russell King 2019-12-09 11:09:35 +0000 130) /* Read remaining buffers */
419a6e5e82ca0 (Russell King 2019-12-09 11:09:35 +0000 131) ret = adfs_dir_read_buffers(sb, indaddr, dirsize, dir);
419a6e5e82ca0 (Russell King 2019-12-09 11:09:35 +0000 132) if (ret)
419a6e5e82ca0 (Russell King 2019-12-09 11:09:35 +0000 133) return ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 134)
016936b32131d (Russell King 2019-12-09 11:10:21 +0000 135) dir->bigtail = t = (struct adfs_bigdirtail *)
419a6e5e82ca0 (Russell King 2019-12-09 11:09:35 +0000 136) (dir->bhs[dir->nr_buffers - 1]->b_data + (sb->s_blocksize - 8));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 137)
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 138) ret = adfs_fplus_validate_tail(h, t);
6674ecab9004d (Russell King 2019-12-09 11:10:57 +0000 139) if (ret) {
419a6e5e82ca0 (Russell King 2019-12-09 11:09:35 +0000 140) adfs_error(sb, "dir %06x has malformed tail", indaddr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 141) goto out;
2f09719af705d (Stuart Swales 2011-03-22 16:35:04 -0700 142) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 143)
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 144) if (adfs_fplus_checkbyte(dir) != t->bigdircheckbyte) {
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 145) adfs_error(sb, "dir %06x checkbyte mismatch\n", indaddr);
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 146) goto out;
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 147) }
d79288b4f61b4 (Russell King 2019-12-09 11:11:08 +0000 148)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 149) dir->parent_id = le32_to_cpu(h->bigdirparent);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 150) return 0;
2f09719af705d (Stuart Swales 2011-03-22 16:35:04 -0700 151)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 152) out:
1dd9f5babfd95 (Russell King 2019-12-09 11:09:20 +0000 153) adfs_dir_relse(dir);
2f09719af705d (Stuart Swales 2011-03-22 16:35:04 -0700 154)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 155) return ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 156) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 157)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 158) static int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 159) adfs_fplus_setpos(struct adfs_dir *dir, unsigned int fpos)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 160) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 161) int ret = -ENOENT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 162)
016936b32131d (Russell King 2019-12-09 11:10:21 +0000 163) if (fpos <= le32_to_cpu(dir->bighead->bigdirentries)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 164) dir->pos = fpos;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 165) ret = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 166) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 167)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 168) return ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 169) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 170)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 171) static int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 172) adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 173) {
016936b32131d (Russell King 2019-12-09 11:10:21 +0000 174) struct adfs_bigdirheader *h = dir->bighead;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 175) struct adfs_bigdirentry bde;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 176) unsigned int offset;
a317120bf7f83 (Russell King 2019-12-09 11:09:30 +0000 177) int ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 178)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 179) if (dir->pos >= le32_to_cpu(h->bigdirentries))
a317120bf7f83 (Russell King 2019-12-09 11:09:30 +0000 180) return -ENOENT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 181)
0db35a02a1c3f (Russell King 2019-12-09 11:10:52 +0000 182) offset = adfs_fplus_offset(h, dir->pos);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 183)
a317120bf7f83 (Russell King 2019-12-09 11:09:30 +0000 184) ret = adfs_dir_copyfrom(&bde, dir, offset,
a317120bf7f83 (Russell King 2019-12-09 11:09:30 +0000 185) sizeof(struct adfs_bigdirentry));
a317120bf7f83 (Russell King 2019-12-09 11:09:30 +0000 186) if (ret)
a317120bf7f83 (Russell King 2019-12-09 11:09:30 +0000 187) return ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 188)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 189) obj->loadaddr = le32_to_cpu(bde.bigdirload);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 190) obj->execaddr = le32_to_cpu(bde.bigdirexec);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 191) obj->size = le32_to_cpu(bde.bigdirlen);
5ed70bb47767d (Russell King 2019-06-04 14:49:57 +0100 192) obj->indaddr = le32_to_cpu(bde.bigdirindaddr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 193) obj->attr = le32_to_cpu(bde.bigdirattr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 194) obj->name_len = le32_to_cpu(bde.bigdirobnamelen);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 195)
0db35a02a1c3f (Russell King 2019-12-09 11:10:52 +0000 196) offset = adfs_fplus_offset(h, le32_to_cpu(h->bigdirentries));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 197) offset += le32_to_cpu(bde.bigdirobnameptr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 198)
a317120bf7f83 (Russell King 2019-12-09 11:09:30 +0000 199) ret = adfs_dir_copyfrom(obj->name, dir, offset, obj->name_len);
a317120bf7f83 (Russell King 2019-12-09 11:09:30 +0000 200) if (ret)
a317120bf7f83 (Russell King 2019-12-09 11:09:30 +0000 201) return ret;
a317120bf7f83 (Russell King 2019-12-09 11:09:30 +0000 202)
411c49bcf32d3 (Russell King 2019-03-24 12:57:32 +0000 203) adfs_object_fixup(dir, obj);
da23ef0549d42 (Stuart Swales 2011-03-22 16:35:06 -0700 204)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 205) dir->pos += 1;
a317120bf7f83 (Russell King 2019-12-09 11:09:30 +0000 206)
a317120bf7f83 (Russell King 2019-12-09 11:09:30 +0000 207) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 208) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 209)
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 210) static int adfs_fplus_iterate(struct adfs_dir *dir, struct dir_context *ctx)
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 211) {
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 212) struct object_info obj;
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 213)
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 214) if ((ctx->pos - 2) >> 32)
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 215) return 0;
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 216)
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 217) if (adfs_fplus_setpos(dir, ctx->pos - 2))
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 218) return 0;
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 219)
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 220) while (!adfs_fplus_getnext(dir, &obj)) {
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 221) if (!dir_emit(ctx, obj.name, obj.name_len,
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 222) obj.indaddr, DT_UNKNOWN))
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 223) break;
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 224) ctx->pos++;
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 225) }
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 226)
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 227) return 0;
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 228) }
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 229)
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 230) static int adfs_fplus_update(struct adfs_dir *dir, struct object_info *obj)
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 231) {
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 232) struct adfs_bigdirheader *h = dir->bighead;
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 233) struct adfs_bigdirentry bde;
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 234) int offset, end, ret;
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 235)
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 236) offset = adfs_fplus_offset(h, 0) - sizeof(bde);
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 237) end = adfs_fplus_offset(h, le32_to_cpu(h->bigdirentries));
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 238)
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 239) do {
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 240) offset += sizeof(bde);
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 241) if (offset >= end) {
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 242) adfs_error(dir->sb, "unable to locate entry to update");
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 243) return -ENOENT;
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 244) }
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 245) ret = adfs_dir_copyfrom(&bde, dir, offset, sizeof(bde));
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 246) if (ret) {
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 247) adfs_error(dir->sb, "error reading directory entry");
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 248) return -ENOENT;
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 249) }
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 250) } while (le32_to_cpu(bde.bigdirindaddr) != obj->indaddr);
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 251)
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 252) bde.bigdirload = cpu_to_le32(obj->loadaddr);
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 253) bde.bigdirexec = cpu_to_le32(obj->execaddr);
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 254) bde.bigdirlen = cpu_to_le32(obj->size);
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 255) bde.bigdirindaddr = cpu_to_le32(obj->indaddr);
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 256) bde.bigdirattr = cpu_to_le32(obj->attr);
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 257)
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 258) return adfs_dir_copyto(dir, offset, &bde, sizeof(bde));
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 259) }
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 260)
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 261) static int adfs_fplus_commit(struct adfs_dir *dir)
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 262) {
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 263) int ret;
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 264)
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 265) /* Increment directory sequence number */
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 266) dir->bighead->startmasseq += 1;
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 267) dir->bigtail->bigdirendmasseq += 1;
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 268)
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 269) /* Update directory check byte */
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 270) dir->bigtail->bigdircheckbyte = adfs_fplus_checkbyte(dir);
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 271)
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 272) /* Make sure the directory still validates correctly */
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 273) ret = adfs_fplus_validate_header(dir->bighead);
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 274) if (ret == 0)
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 275) ret = adfs_fplus_validate_tail(dir->bighead, dir->bigtail);
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 276)
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 277) return ret;
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 278) }
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 279)
0125f504ed320 (Julia Lawall 2015-11-21 16:15:37 +0100 280) const struct adfs_dir_ops adfs_fplus_dir_ops = {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 281) .read = adfs_fplus_read,
4287e4deb1280 (Russell King 2019-12-09 11:10:16 +0000 282) .iterate = adfs_fplus_iterate,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 283) .setpos = adfs_fplus_setpos,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 284) .getnext = adfs_fplus_getnext,
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 285) .update = adfs_fplus_update,
a464152f2e6df (Russell King 2019-12-09 11:11:13 +0000 286) .commit = adfs_fplus_commit,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 287) };