^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * linux/fs/adfs/dir_f.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 1997-1999 Russell King
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * E and F format directory handling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include "adfs.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include "dir_f.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Read an (unaligned) value of length 1..4 bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) static inline unsigned int adfs_readval(unsigned char *p, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) unsigned int val = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) switch (len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) case 4: val |= p[3] << 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) case 3: val |= p[2] << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) case 2: val |= p[1] << 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) default: val |= p[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) return val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static inline void adfs_writeval(unsigned char *p, int len, unsigned int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) switch (len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) case 4: p[3] = val >> 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) case 3: p[2] = val >> 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) case 2: p[1] = val >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) default: p[0] = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define ror13(v) ((v >> 13) | (v << 19))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define dir_u8(idx) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) ({ int _buf = idx >> blocksize_bits; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) int _off = idx - (_buf << blocksize_bits);\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) *(u8 *)(bh[_buf]->b_data + _off); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) })
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define dir_u32(idx) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) ({ int _buf = idx >> blocksize_bits; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) int _off = idx - (_buf << blocksize_bits);\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) *(__le32 *)(bh[_buf]->b_data + _off); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) })
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define bufoff(_bh,_idx) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) ({ int _buf = _idx >> blocksize_bits; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) int _off = _idx - (_buf << blocksize_bits);\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) (void *)(_bh[_buf]->b_data + _off); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) })
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * There are some algorithms that are nice in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * assembler, but a bitch in C... This is one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * of them.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static u8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) adfs_dir_checkbyte(const struct adfs_dir *dir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct buffer_head * const *bh = dir->bh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) const int blocksize_bits = dir->sb->s_blocksize_bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) union { __le32 *ptr32; u8 *ptr8; } ptr, end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) u32 dircheck = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) int last = 5 - 26;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * Accumulate each word up to the last whole
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * word of the last directory entry. This
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * can spread across several buffer heads.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) last += 26;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) dircheck = le32_to_cpu(dir_u32(i)) ^ ror13(dircheck);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) i += sizeof(u32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) } while (i < (last & ~3));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) } while (dir_u8(last) != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * Accumulate the last few bytes. These
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * bytes will be within the same bh.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (i != last) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) ptr.ptr8 = bufoff(bh, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) end.ptr8 = ptr.ptr8 + last - i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) dircheck = *ptr.ptr8++ ^ ror13(dircheck);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) } while (ptr.ptr8 < end.ptr8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * The directory tail is in the final bh
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * Note that contary to the RISC OS PRMs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * the first few bytes are NOT included
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * in the check. All bytes are in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * same bh.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) ptr.ptr8 = bufoff(bh, 2008);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) end.ptr8 = ptr.ptr8 + 36;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) __le32 v = *ptr.ptr32++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) dircheck = le32_to_cpu(v) ^ ror13(dircheck);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) } while (ptr.ptr32 < end.ptr32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return (dircheck ^ (dircheck >> 8) ^ (dircheck >> 16) ^ (dircheck >> 24)) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) static int adfs_f_validate(struct adfs_dir *dir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) struct adfs_dirheader *head = dir->dirhead;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) struct adfs_newdirtail *tail = dir->newtail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) if (head->startmasseq != tail->endmasseq ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) tail->dirlastmask || tail->reserved[0] || tail->reserved[1] ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) (memcmp(&head->startname, "Nick", 4) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) memcmp(&head->startname, "Hugo", 4)) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) memcmp(&head->startname, &tail->endname, 4) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) adfs_dir_checkbyte(dir) != tail->dircheckbyte)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) /* Read and check that a directory is valid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) static int adfs_f_read(struct super_block *sb, u32 indaddr, unsigned int size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) struct adfs_dir *dir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) const unsigned int blocksize_bits = sb->s_blocksize_bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (size && size != ADFS_NEWDIR_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) ret = adfs_dir_read_buffers(sb, indaddr, ADFS_NEWDIR_SIZE, dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) dir->dirhead = bufoff(dir->bh, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) dir->newtail = bufoff(dir->bh, 2007);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (adfs_f_validate(dir))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) goto bad_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) dir->parent_id = adfs_readval(dir->newtail->dirparent, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) bad_dir:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) adfs_error(sb, "dir %06x is corrupted", indaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) adfs_dir_relse(dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) * convert a disk-based directory entry to a Linux ADFS directory entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) adfs_dir2obj(struct adfs_dir *dir, struct object_info *obj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) struct adfs_direntry *de)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) unsigned int name_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) for (name_len = 0; name_len < ADFS_F_NAME_LEN; name_len++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) if (de->dirobname[name_len] < ' ')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) obj->name[name_len] = de->dirobname[name_len];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) obj->name_len = name_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) obj->indaddr = adfs_readval(de->dirinddiscadd, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) obj->loadaddr = adfs_readval(de->dirload, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) obj->execaddr = adfs_readval(de->direxec, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) obj->size = adfs_readval(de->dirlen, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) obj->attr = de->newdiratts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) adfs_object_fixup(dir, obj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) * convert a Linux ADFS directory entry to a disk-based directory entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) adfs_obj2dir(struct adfs_direntry *de, struct object_info *obj)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) adfs_writeval(de->dirinddiscadd, 3, obj->indaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) adfs_writeval(de->dirload, 4, obj->loadaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) adfs_writeval(de->direxec, 4, obj->execaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) adfs_writeval(de->dirlen, 4, obj->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) de->newdiratts = obj->attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) * get a directory entry. Note that the caller is responsible
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) * for holding the relevant locks.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) __adfs_dir_get(struct adfs_dir *dir, int pos, struct object_info *obj)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) struct adfs_direntry de;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) ret = adfs_dir_copyfrom(&de, dir, pos, 26);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (!de.dirobname[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) adfs_dir2obj(dir, obj, &de);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) adfs_f_setpos(struct adfs_dir *dir, unsigned int fpos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if (fpos >= ADFS_NUM_DIR_ENTRIES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) dir->pos = 5 + fpos * 26;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) adfs_f_getnext(struct adfs_dir *dir, struct object_info *obj)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) unsigned int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) ret = __adfs_dir_get(dir, dir->pos, obj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) dir->pos += 26;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) static int adfs_f_iterate(struct adfs_dir *dir, struct dir_context *ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) struct object_info obj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) int pos = 5 + (ctx->pos - 2) * 26;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) while (ctx->pos < 2 + ADFS_NUM_DIR_ENTRIES) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (__adfs_dir_get(dir, pos, &obj))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) if (!dir_emit(ctx, obj.name, obj.name_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) obj.indaddr, DT_UNKNOWN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) pos += 26;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) ctx->pos++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) static int adfs_f_update(struct adfs_dir *dir, struct object_info *obj)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) struct adfs_direntry de;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) int offset, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) offset = 5 - (int)sizeof(de);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) offset += sizeof(de);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) ret = adfs_dir_copyfrom(&de, dir, offset, sizeof(de));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) adfs_error(dir->sb, "error reading directory entry");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) if (!de.dirobname[0]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) adfs_error(dir->sb, "unable to locate entry to update");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) } while (adfs_readval(de.dirinddiscadd, 3) != obj->indaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) /* Update the directory entry with the new object state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) adfs_obj2dir(&de, obj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) /* Write the directory entry back to the directory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) return adfs_dir_copyto(dir, offset, &de, 26);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) static int adfs_f_commit(struct adfs_dir *dir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) /* Increment directory sequence number */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) dir->dirhead->startmasseq += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) dir->newtail->endmasseq += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) /* Update directory check byte */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) dir->newtail->dircheckbyte = adfs_dir_checkbyte(dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) /* Make sure the directory still validates correctly */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) ret = adfs_f_validate(dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) adfs_msg(dir->sb, KERN_ERR, "error: update broke directory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) const struct adfs_dir_ops adfs_f_dir_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) .read = adfs_f_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) .iterate = adfs_f_iterate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) .setpos = adfs_f_setpos,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) .getnext = adfs_f_getnext,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) .update = adfs_f_update,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) .commit = adfs_f_commit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) };