hc
2023-12-09 b22da3d8526a935aa31e086e63f60ff3246cb61c
kernel/fs/adfs/dir_f.c
....@@ -1,19 +1,13 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * linux/fs/adfs/dir_f.c
34 *
45 * Copyright (C) 1997-1999 Russell King
56 *
6
- * This program is free software; you can redistribute it and/or modify
7
- * it under the terms of the GNU General Public License version 2 as
8
- * published by the Free Software Foundation.
9
- *
107 * E and F format directory handling
118 */
12
-#include <linux/buffer_head.h>
139 #include "adfs.h"
1410 #include "dir_f.h"
15
-
16
-static void adfs_f_free(struct adfs_dir *dir);
1711
1812 /*
1913 * Read an (unaligned) value of length 1..4 bytes
....@@ -24,8 +18,11 @@
2418
2519 switch (len) {
2620 case 4: val |= p[3] << 24;
21
+ fallthrough;
2722 case 3: val |= p[2] << 16;
23
+ fallthrough;
2824 case 2: val |= p[1] << 8;
25
+ fallthrough;
2926 default: val |= p[0];
3027 }
3128 return val;
....@@ -35,25 +32,13 @@
3532 {
3633 switch (len) {
3734 case 4: p[3] = val >> 24;
35
+ fallthrough;
3836 case 3: p[2] = val >> 16;
37
+ fallthrough;
3938 case 2: p[1] = val >> 8;
39
+ fallthrough;
4040 default: p[0] = val;
4141 }
42
-}
43
-
44
-static inline int adfs_readname(char *buf, char *ptr, int maxlen)
45
-{
46
- char *old_buf = buf;
47
-
48
- while ((unsigned char)*ptr >= ' ' && maxlen--) {
49
- if (*ptr == '/')
50
- *buf++ = '.';
51
- else
52
- *buf++ = *ptr;
53
- ptr++;
54
- }
55
-
56
- return buf - old_buf;
5742 }
5843
5944 #define ror13(v) ((v >> 13) | (v << 19))
....@@ -73,7 +58,7 @@
7358 #define bufoff(_bh,_idx) \
7459 ({ int _buf = _idx >> blocksize_bits; \
7560 int _off = _idx - (_buf << blocksize_bits);\
76
- (u8 *)(_bh[_buf]->b_data + _off); \
61
+ (void *)(_bh[_buf]->b_data + _off); \
7762 })
7863
7964 /*
....@@ -136,69 +121,49 @@
136121 return (dircheck ^ (dircheck >> 8) ^ (dircheck >> 16) ^ (dircheck >> 24)) & 0xff;
137122 }
138123
139
-/*
140
- * Read and check that a directory is valid
141
- */
142
-static int
143
-adfs_dir_read(struct super_block *sb, unsigned long object_id,
144
- unsigned int size, struct adfs_dir *dir)
124
+static int adfs_f_validate(struct adfs_dir *dir)
125
+{
126
+ struct adfs_dirheader *head = dir->dirhead;
127
+ struct adfs_newdirtail *tail = dir->newtail;
128
+
129
+ if (head->startmasseq != tail->endmasseq ||
130
+ tail->dirlastmask || tail->reserved[0] || tail->reserved[1] ||
131
+ (memcmp(&head->startname, "Nick", 4) &&
132
+ memcmp(&head->startname, "Hugo", 4)) ||
133
+ memcmp(&head->startname, &tail->endname, 4) ||
134
+ adfs_dir_checkbyte(dir) != tail->dircheckbyte)
135
+ return -EIO;
136
+
137
+ return 0;
138
+}
139
+
140
+/* Read and check that a directory is valid */
141
+static int adfs_f_read(struct super_block *sb, u32 indaddr, unsigned int size,
142
+ struct adfs_dir *dir)
145143 {
146144 const unsigned int blocksize_bits = sb->s_blocksize_bits;
147
- int blk = 0;
145
+ int ret;
148146
149
- /*
150
- * Directories which are not a multiple of 2048 bytes
151
- * are considered bad v2 [3.6]
152
- */
153
- if (size & 2047)
147
+ if (size && size != ADFS_NEWDIR_SIZE)
148
+ return -EIO;
149
+
150
+ ret = adfs_dir_read_buffers(sb, indaddr, ADFS_NEWDIR_SIZE, dir);
151
+ if (ret)
152
+ return ret;
153
+
154
+ dir->dirhead = bufoff(dir->bh, 0);
155
+ dir->newtail = bufoff(dir->bh, 2007);
156
+
157
+ if (adfs_f_validate(dir))
154158 goto bad_dir;
155159
156
- size >>= blocksize_bits;
157
-
158
- dir->nr_buffers = 0;
159
- dir->sb = sb;
160
-
161
- for (blk = 0; blk < size; blk++) {
162
- int phys;
163
-
164
- phys = __adfs_block_map(sb, object_id, blk);
165
- if (!phys) {
166
- adfs_error(sb, "dir object %lX has a hole at offset %d",
167
- object_id, blk);
168
- goto release_buffers;
169
- }
170
-
171
- dir->bh[blk] = sb_bread(sb, phys);
172
- if (!dir->bh[blk])
173
- goto release_buffers;
174
- }
175
-
176
- memcpy(&dir->dirhead, bufoff(dir->bh, 0), sizeof(dir->dirhead));
177
- memcpy(&dir->dirtail, bufoff(dir->bh, 2007), sizeof(dir->dirtail));
178
-
179
- if (dir->dirhead.startmasseq != dir->dirtail.new.endmasseq ||
180
- memcmp(&dir->dirhead.startname, &dir->dirtail.new.endname, 4))
181
- goto bad_dir;
182
-
183
- if (memcmp(&dir->dirhead.startname, "Nick", 4) &&
184
- memcmp(&dir->dirhead.startname, "Hugo", 4))
185
- goto bad_dir;
186
-
187
- if (adfs_dir_checkbyte(dir) != dir->dirtail.new.dircheckbyte)
188
- goto bad_dir;
189
-
190
- dir->nr_buffers = blk;
160
+ dir->parent_id = adfs_readval(dir->newtail->dirparent, 3);
191161
192162 return 0;
193163
194164 bad_dir:
195
- adfs_error(sb, "corrupted directory fragment %lX",
196
- object_id);
197
-release_buffers:
198
- for (blk -= 1; blk >= 0; blk -= 1)
199
- brelse(dir->bh[blk]);
200
-
201
- dir->sb = NULL;
165
+ adfs_error(sb, "dir %06x is corrupted", indaddr);
166
+ adfs_dir_relse(dir);
202167
203168 return -EIO;
204169 }
....@@ -210,29 +175,23 @@
210175 adfs_dir2obj(struct adfs_dir *dir, struct object_info *obj,
211176 struct adfs_direntry *de)
212177 {
213
- obj->name_len = adfs_readname(obj->name, de->dirobname, ADFS_F_NAME_LEN);
214
- obj->file_id = adfs_readval(de->dirinddiscadd, 3);
178
+ unsigned int name_len;
179
+
180
+ for (name_len = 0; name_len < ADFS_F_NAME_LEN; name_len++) {
181
+ if (de->dirobname[name_len] < ' ')
182
+ break;
183
+
184
+ obj->name[name_len] = de->dirobname[name_len];
185
+ }
186
+
187
+ obj->name_len = name_len;
188
+ obj->indaddr = adfs_readval(de->dirinddiscadd, 3);
215189 obj->loadaddr = adfs_readval(de->dirload, 4);
216190 obj->execaddr = adfs_readval(de->direxec, 4);
217191 obj->size = adfs_readval(de->dirlen, 4);
218192 obj->attr = de->newdiratts;
219
- obj->filetype = -1;
220193
221
- /*
222
- * object is a file and is filetyped and timestamped?
223
- * RISC OS 12-bit filetype is stored in load_address[19:8]
224
- */
225
- if ((0 == (obj->attr & ADFS_NDA_DIRECTORY)) &&
226
- (0xfff00000 == (0xfff00000 & obj->loadaddr))) {
227
- obj->filetype = (__u16) ((0x000fff00 & obj->loadaddr) >> 8);
228
-
229
- /* optionally append the ,xyz hex filetype suffix */
230
- if (ADFS_SB(dir->sb)->s_ftsuffix)
231
- obj->name_len +=
232
- append_filetype_suffix(
233
- &obj->name[obj->name_len],
234
- obj->filetype);
235
- }
194
+ adfs_object_fixup(dir, obj);
236195 }
237196
238197 /*
....@@ -241,7 +200,7 @@
241200 static inline void
242201 adfs_obj2dir(struct adfs_direntry *de, struct object_info *obj)
243202 {
244
- adfs_writeval(de->dirinddiscadd, 3, obj->file_id);
203
+ adfs_writeval(de->dirinddiscadd, 3, obj->indaddr);
245204 adfs_writeval(de->dirload, 4, obj->loadaddr);
246205 adfs_writeval(de->direxec, 4, obj->execaddr);
247206 adfs_writeval(de->dirlen, 4, obj->size);
....@@ -255,24 +214,12 @@
255214 static int
256215 __adfs_dir_get(struct adfs_dir *dir, int pos, struct object_info *obj)
257216 {
258
- struct super_block *sb = dir->sb;
259217 struct adfs_direntry de;
260
- int thissize, buffer, offset;
218
+ int ret;
261219
262
- buffer = pos >> sb->s_blocksize_bits;
263
-
264
- if (buffer > dir->nr_buffers)
265
- return -EINVAL;
266
-
267
- offset = pos & (sb->s_blocksize - 1);
268
- thissize = sb->s_blocksize - offset;
269
- if (thissize > 26)
270
- thissize = 26;
271
-
272
- memcpy(&de, dir->bh[buffer]->b_data + offset, thissize);
273
- if (thissize != 26)
274
- memcpy(((char *)&de) + thissize, dir->bh[buffer + 1]->b_data,
275
- 26 - thissize);
220
+ ret = adfs_dir_copyfrom(&de, dir, pos, 26);
221
+ if (ret)
222
+ return ret;
276223
277224 if (!de.dirobname[0])
278225 return -ENOENT;
....@@ -280,90 +227,6 @@
280227 adfs_dir2obj(dir, obj, &de);
281228
282229 return 0;
283
-}
284
-
285
-static int
286
-__adfs_dir_put(struct adfs_dir *dir, int pos, struct object_info *obj)
287
-{
288
- struct super_block *sb = dir->sb;
289
- struct adfs_direntry de;
290
- int thissize, buffer, offset;
291
-
292
- buffer = pos >> sb->s_blocksize_bits;
293
-
294
- if (buffer > dir->nr_buffers)
295
- return -EINVAL;
296
-
297
- offset = pos & (sb->s_blocksize - 1);
298
- thissize = sb->s_blocksize - offset;
299
- if (thissize > 26)
300
- thissize = 26;
301
-
302
- /*
303
- * Get the entry in total
304
- */
305
- memcpy(&de, dir->bh[buffer]->b_data + offset, thissize);
306
- if (thissize != 26)
307
- memcpy(((char *)&de) + thissize, dir->bh[buffer + 1]->b_data,
308
- 26 - thissize);
309
-
310
- /*
311
- * update it
312
- */
313
- adfs_obj2dir(&de, obj);
314
-
315
- /*
316
- * Put the new entry back
317
- */
318
- memcpy(dir->bh[buffer]->b_data + offset, &de, thissize);
319
- if (thissize != 26)
320
- memcpy(dir->bh[buffer + 1]->b_data, ((char *)&de) + thissize,
321
- 26 - thissize);
322
-
323
- return 0;
324
-}
325
-
326
-/*
327
- * the caller is responsible for holding the necessary
328
- * locks.
329
- */
330
-static int
331
-adfs_dir_find_entry(struct adfs_dir *dir, unsigned long object_id)
332
-{
333
- int pos, ret;
334
-
335
- ret = -ENOENT;
336
-
337
- for (pos = 5; pos < ADFS_NUM_DIR_ENTRIES * 26 + 5; pos += 26) {
338
- struct object_info obj;
339
-
340
- if (!__adfs_dir_get(dir, pos, &obj))
341
- break;
342
-
343
- if (obj.file_id == object_id) {
344
- ret = pos;
345
- break;
346
- }
347
- }
348
-
349
- return ret;
350
-}
351
-
352
-static int
353
-adfs_f_read(struct super_block *sb, unsigned int id, unsigned int sz, struct adfs_dir *dir)
354
-{
355
- int ret;
356
-
357
- if (sz != ADFS_NEWDIR_SIZE)
358
- return -EIO;
359
-
360
- ret = adfs_dir_read(sb, id, sz, dir);
361
- if (ret)
362
- adfs_error(sb, "unable to read directory");
363
- else
364
- dir->parent_id = adfs_readval(dir->dirtail.new.dirparent, 3);
365
-
366
- return ret;
367230 }
368231
369232 static int
....@@ -388,99 +251,74 @@
388251 return ret;
389252 }
390253
391
-static int
392
-adfs_f_update(struct adfs_dir *dir, struct object_info *obj)
254
+static int adfs_f_iterate(struct adfs_dir *dir, struct dir_context *ctx)
393255 {
394
- struct super_block *sb = dir->sb;
395
- int ret, i;
256
+ struct object_info obj;
257
+ int pos = 5 + (ctx->pos - 2) * 26;
396258
397
- ret = adfs_dir_find_entry(dir, obj->file_id);
398
- if (ret < 0) {
399
- adfs_error(dir->sb, "unable to locate entry to update");
400
- goto out;
259
+ while (ctx->pos < 2 + ADFS_NUM_DIR_ENTRIES) {
260
+ if (__adfs_dir_get(dir, pos, &obj))
261
+ break;
262
+ if (!dir_emit(ctx, obj.name, obj.name_len,
263
+ obj.indaddr, DT_UNKNOWN))
264
+ break;
265
+ pos += 26;
266
+ ctx->pos++;
401267 }
268
+ return 0;
269
+}
402270
403
- __adfs_dir_put(dir, ret, obj);
404
-
405
- /*
406
- * Increment directory sequence number
407
- */
408
- dir->bh[0]->b_data[0] += 1;
409
- dir->bh[dir->nr_buffers - 1]->b_data[sb->s_blocksize - 6] += 1;
271
+static int adfs_f_update(struct adfs_dir *dir, struct object_info *obj)
272
+{
273
+ struct adfs_direntry de;
274
+ int offset, ret;
410275
411
- ret = adfs_dir_checkbyte(dir);
412
- /*
413
- * Update directory check byte
414
- */
415
- dir->bh[dir->nr_buffers - 1]->b_data[sb->s_blocksize - 1] = ret;
276
+ offset = 5 - (int)sizeof(de);
416277
417
-#if 1
418
- {
419
- const unsigned int blocksize_bits = sb->s_blocksize_bits;
278
+ do {
279
+ offset += sizeof(de);
280
+ ret = adfs_dir_copyfrom(&de, dir, offset, sizeof(de));
281
+ if (ret) {
282
+ adfs_error(dir->sb, "error reading directory entry");
283
+ return -ENOENT;
284
+ }
285
+ if (!de.dirobname[0]) {
286
+ adfs_error(dir->sb, "unable to locate entry to update");
287
+ return -ENOENT;
288
+ }
289
+ } while (adfs_readval(de.dirinddiscadd, 3) != obj->indaddr);
420290
421
- memcpy(&dir->dirhead, bufoff(dir->bh, 0), sizeof(dir->dirhead));
422
- memcpy(&dir->dirtail, bufoff(dir->bh, 2007), sizeof(dir->dirtail));
291
+ /* Update the directory entry with the new object state */
292
+ adfs_obj2dir(&de, obj);
423293
424
- if (dir->dirhead.startmasseq != dir->dirtail.new.endmasseq ||
425
- memcmp(&dir->dirhead.startname, &dir->dirtail.new.endname, 4))
426
- goto bad_dir;
294
+ /* Write the directory entry back to the directory */
295
+ return adfs_dir_copyto(dir, offset, &de, 26);
296
+}
427297
428
- if (memcmp(&dir->dirhead.startname, "Nick", 4) &&
429
- memcmp(&dir->dirhead.startname, "Hugo", 4))
430
- goto bad_dir;
298
+static int adfs_f_commit(struct adfs_dir *dir)
299
+{
300
+ int ret;
431301
432
- if (adfs_dir_checkbyte(dir) != dir->dirtail.new.dircheckbyte)
433
- goto bad_dir;
434
- }
435
-#endif
436
- for (i = dir->nr_buffers - 1; i >= 0; i--)
437
- mark_buffer_dirty(dir->bh[i]);
302
+ /* Increment directory sequence number */
303
+ dir->dirhead->startmasseq += 1;
304
+ dir->newtail->endmasseq += 1;
438305
439
- ret = 0;
440
-out:
306
+ /* Update directory check byte */
307
+ dir->newtail->dircheckbyte = adfs_dir_checkbyte(dir);
308
+
309
+ /* Make sure the directory still validates correctly */
310
+ ret = adfs_f_validate(dir);
311
+ if (ret)
312
+ adfs_msg(dir->sb, KERN_ERR, "error: update broke directory");
313
+
441314 return ret;
442
-#if 1
443
-bad_dir:
444
- adfs_error(dir->sb, "whoops! I broke a directory!");
445
- return -EIO;
446
-#endif
447
-}
448
-
449
-static int
450
-adfs_f_sync(struct adfs_dir *dir)
451
-{
452
- int err = 0;
453
- int i;
454
-
455
- for (i = dir->nr_buffers - 1; i >= 0; i--) {
456
- struct buffer_head *bh = dir->bh[i];
457
- sync_dirty_buffer(bh);
458
- if (buffer_req(bh) && !buffer_uptodate(bh))
459
- err = -EIO;
460
- }
461
-
462
- return err;
463
-}
464
-
465
-static void
466
-adfs_f_free(struct adfs_dir *dir)
467
-{
468
- int i;
469
-
470
- for (i = dir->nr_buffers - 1; i >= 0; i--) {
471
- brelse(dir->bh[i]);
472
- dir->bh[i] = NULL;
473
- }
474
-
475
- dir->nr_buffers = 0;
476
- dir->sb = NULL;
477315 }
478316
479317 const struct adfs_dir_ops adfs_f_dir_ops = {
480318 .read = adfs_f_read,
319
+ .iterate = adfs_f_iterate,
481320 .setpos = adfs_f_setpos,
482321 .getnext = adfs_f_getnext,
483322 .update = adfs_f_update,
484
- .sync = adfs_f_sync,
485
- .free = adfs_f_free
323
+ .commit = adfs_f_commit,
486324 };