]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - fs/adfs/dir_fplus.c
fs/adfs: bigdir: factor out directory entry offset calculation
[mirror_ubuntu-hirsute-kernel.git] / fs / adfs / dir_fplus.c
CommitLineData
d2912cb1 1// SPDX-License-Identifier: GPL-2.0-only
1da177e4
LT
2/*
3 * linux/fs/adfs/dir_fplus.c
4 *
5 * Copyright (C) 1997-1999 Russell King
1da177e4 6 */
1da177e4
LT
7#include "adfs.h"
8#include "dir_fplus.h"
9
0db35a02
RK
10/* Return the byte offset to directory entry pos */
11static unsigned int adfs_fplus_offset(const struct adfs_bigdirheader *h,
12 unsigned int pos)
13{
14 return offsetof(struct adfs_bigdirheader, bigdirname) +
15 ALIGN(le32_to_cpu(h->bigdirnamelen), 4) +
16 pos * sizeof(struct adfs_bigdirentry);
17}
18
419a6e5e
RK
19static int adfs_fplus_read(struct super_block *sb, u32 indaddr,
20 unsigned int size, struct adfs_dir *dir)
1da177e4
LT
21{
22 struct adfs_bigdirheader *h;
23 struct adfs_bigdirtail *t;
419a6e5e
RK
24 unsigned int dirsize;
25 int ret;
1da177e4 26
419a6e5e
RK
27 /* Read first buffer */
28 ret = adfs_dir_read_buffers(sb, indaddr, sb->s_blocksize, dir);
29 if (ret)
30 return ret;
1da177e4 31
016936b3 32 dir->bighead = h = (void *)dir->bhs[0]->b_data;
419a6e5e
RK
33 dirsize = le32_to_cpu(h->bigdirsize);
34 if (dirsize != size) {
ceb3b106 35 adfs_msg(sb, KERN_WARNING,
419a6e5e
RK
36 "dir %06x header size %X does not match directory size %X",
37 indaddr, dirsize, size);
1da177e4
LT
38 }
39
40 if (h->bigdirversion[0] != 0 || h->bigdirversion[1] != 0 ||
41 h->bigdirversion[2] != 0 || size & 2047 ||
2f09719a 42 h->bigdirstartname != cpu_to_le32(BIGDIRSTARTNAME)) {
419a6e5e 43 adfs_error(sb, "dir %06x has malformed header", indaddr);
1da177e4 44 goto out;
2f09719a 45 }
1da177e4 46
419a6e5e
RK
47 /* Read remaining buffers */
48 ret = adfs_dir_read_buffers(sb, indaddr, dirsize, dir);
49 if (ret)
50 return ret;
1da177e4 51
016936b3 52 dir->bigtail = t = (struct adfs_bigdirtail *)
419a6e5e 53 (dir->bhs[dir->nr_buffers - 1]->b_data + (sb->s_blocksize - 8));
1da177e4
LT
54
55 if (t->bigdirendname != cpu_to_le32(BIGDIRENDNAME) ||
56 t->bigdirendmasseq != h->startmasseq ||
2f09719a 57 t->reserved[0] != 0 || t->reserved[1] != 0) {
419a6e5e 58 adfs_error(sb, "dir %06x has malformed tail", indaddr);
1da177e4 59 goto out;
2f09719a 60 }
1da177e4
LT
61
62 dir->parent_id = le32_to_cpu(h->bigdirparent);
1da177e4 63 return 0;
2f09719a 64
1da177e4 65out:
1dd9f5ba 66 adfs_dir_relse(dir);
2f09719a 67
1da177e4
LT
68 return ret;
69}
70
71static int
72adfs_fplus_setpos(struct adfs_dir *dir, unsigned int fpos)
73{
1da177e4
LT
74 int ret = -ENOENT;
75
016936b3 76 if (fpos <= le32_to_cpu(dir->bighead->bigdirentries)) {
1da177e4
LT
77 dir->pos = fpos;
78 ret = 0;
79 }
80
81 return ret;
82}
83
1da177e4
LT
84static int
85adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
86{
016936b3 87 struct adfs_bigdirheader *h = dir->bighead;
1da177e4
LT
88 struct adfs_bigdirentry bde;
89 unsigned int offset;
a317120b 90 int ret;
1da177e4
LT
91
92 if (dir->pos >= le32_to_cpu(h->bigdirentries))
a317120b 93 return -ENOENT;
1da177e4 94
0db35a02 95 offset = adfs_fplus_offset(h, dir->pos);
1da177e4 96
a317120b
RK
97 ret = adfs_dir_copyfrom(&bde, dir, offset,
98 sizeof(struct adfs_bigdirentry));
99 if (ret)
100 return ret;
1da177e4
LT
101
102 obj->loadaddr = le32_to_cpu(bde.bigdirload);
103 obj->execaddr = le32_to_cpu(bde.bigdirexec);
104 obj->size = le32_to_cpu(bde.bigdirlen);
5ed70bb4 105 obj->indaddr = le32_to_cpu(bde.bigdirindaddr);
1da177e4
LT
106 obj->attr = le32_to_cpu(bde.bigdirattr);
107 obj->name_len = le32_to_cpu(bde.bigdirobnamelen);
108
0db35a02 109 offset = adfs_fplus_offset(h, le32_to_cpu(h->bigdirentries));
1da177e4
LT
110 offset += le32_to_cpu(bde.bigdirobnameptr);
111
a317120b
RK
112 ret = adfs_dir_copyfrom(obj->name, dir, offset, obj->name_len);
113 if (ret)
114 return ret;
115
411c49bc 116 adfs_object_fixup(dir, obj);
da23ef05 117
1da177e4 118 dir->pos += 1;
a317120b
RK
119
120 return 0;
1da177e4
LT
121}
122
4287e4de
RK
123static int adfs_fplus_iterate(struct adfs_dir *dir, struct dir_context *ctx)
124{
125 struct object_info obj;
126
127 if ((ctx->pos - 2) >> 32)
128 return 0;
129
130 if (adfs_fplus_setpos(dir, ctx->pos - 2))
131 return 0;
132
133 while (!adfs_fplus_getnext(dir, &obj)) {
134 if (!dir_emit(ctx, obj.name, obj.name_len,
135 obj.indaddr, DT_UNKNOWN))
136 break;
137 ctx->pos++;
138 }
139
140 return 0;
141}
142
0125f504 143const struct adfs_dir_ops adfs_fplus_dir_ops = {
1da177e4 144 .read = adfs_fplus_read,
4287e4de 145 .iterate = adfs_fplus_iterate,
1da177e4
LT
146 .setpos = adfs_fplus_setpos,
147 .getnext = adfs_fplus_getnext,
1da177e4 148};