2 * linux/fs/adfs/dir_fplus.c
4 * Copyright (C) 1997-1999 Russell King
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.
10 #include <linux/errno.h>
12 #include <linux/adfs_fs.h>
13 #include <linux/time.h>
14 #include <linux/stat.h>
15 #include <linux/spinlock.h>
16 #include <linux/buffer_head.h>
17 #include <linux/string.h>
20 #include "dir_fplus.h"
23 adfs_fplus_read(struct super_block
*sb
, unsigned int id
, unsigned int sz
, struct adfs_dir
*dir
)
25 struct adfs_bigdirheader
*h
;
26 struct adfs_bigdirtail
*t
;
28 unsigned int blk
, size
;
33 block
= __adfs_block_map(sb
, id
, 0);
35 adfs_error(sb
, "dir object %X has a hole at offset 0", id
);
39 dir
->bh
[0] = sb_bread(sb
, block
);
44 h
= (struct adfs_bigdirheader
*)dir
->bh
[0]->b_data
;
45 size
= le32_to_cpu(h
->bigdirsize
);
47 printk(KERN_WARNING
"adfs: adfs_fplus_read: directory header size\n"
48 " does not match directory size\n");
51 if (h
->bigdirversion
[0] != 0 || h
->bigdirversion
[1] != 0 ||
52 h
->bigdirversion
[2] != 0 || size
& 2047 ||
53 h
->bigdirstartname
!= cpu_to_le32(BIGDIRSTARTNAME
))
56 size
>>= sb
->s_blocksize_bits
;
57 for (blk
= 1; blk
< size
; blk
++) {
58 block
= __adfs_block_map(sb
, id
, blk
);
60 adfs_error(sb
, "dir object %X has a hole at offset %d", id
, blk
);
64 dir
->bh
[blk
] = sb_bread(sb
, block
);
67 dir
->nr_buffers
= blk
;
70 t
= (struct adfs_bigdirtail
*)(dir
->bh
[size
- 1]->b_data
+ (sb
->s_blocksize
- 8));
72 if (t
->bigdirendname
!= cpu_to_le32(BIGDIRENDNAME
) ||
73 t
->bigdirendmasseq
!= h
->startmasseq
||
74 t
->reserved
[0] != 0 || t
->reserved
[1] != 0)
77 dir
->parent_id
= le32_to_cpu(h
->bigdirparent
);
81 for (i
= 0; i
< dir
->nr_buffers
; i
++)
88 adfs_fplus_setpos(struct adfs_dir
*dir
, unsigned int fpos
)
90 struct adfs_bigdirheader
*h
= (struct adfs_bigdirheader
*)dir
->bh
[0]->b_data
;
93 if (fpos
<= le32_to_cpu(h
->bigdirentries
)) {
102 dir_memcpy(struct adfs_dir
*dir
, unsigned int offset
, void *to
, int len
)
104 struct super_block
*sb
= dir
->sb
;
105 unsigned int buffer
, partial
, remainder
;
107 buffer
= offset
>> sb
->s_blocksize_bits
;
108 offset
&= sb
->s_blocksize
- 1;
110 partial
= sb
->s_blocksize
- offset
;
113 memcpy(to
, dir
->bh
[buffer
]->b_data
+ offset
, len
);
115 char *c
= (char *)to
;
117 remainder
= len
- partial
;
119 memcpy(c
, dir
->bh
[buffer
]->b_data
+ offset
, partial
);
120 memcpy(c
+ partial
, dir
->bh
[buffer
+ 1]->b_data
, remainder
);
125 adfs_fplus_getnext(struct adfs_dir
*dir
, struct object_info
*obj
)
127 struct adfs_bigdirheader
*h
= (struct adfs_bigdirheader
*)dir
->bh
[0]->b_data
;
128 struct adfs_bigdirentry bde
;
130 int i
, ret
= -ENOENT
;
132 if (dir
->pos
>= le32_to_cpu(h
->bigdirentries
))
135 offset
= offsetof(struct adfs_bigdirheader
, bigdirname
);
136 offset
+= ((le32_to_cpu(h
->bigdirnamelen
) + 4) & ~3);
137 offset
+= dir
->pos
* sizeof(struct adfs_bigdirentry
);
139 dir_memcpy(dir
, offset
, &bde
, sizeof(struct adfs_bigdirentry
));
141 obj
->loadaddr
= le32_to_cpu(bde
.bigdirload
);
142 obj
->execaddr
= le32_to_cpu(bde
.bigdirexec
);
143 obj
->size
= le32_to_cpu(bde
.bigdirlen
);
144 obj
->file_id
= le32_to_cpu(bde
.bigdirindaddr
);
145 obj
->attr
= le32_to_cpu(bde
.bigdirattr
);
146 obj
->name_len
= le32_to_cpu(bde
.bigdirobnamelen
);
148 offset
= offsetof(struct adfs_bigdirheader
, bigdirname
);
149 offset
+= ((le32_to_cpu(h
->bigdirnamelen
) + 4) & ~3);
150 offset
+= le32_to_cpu(h
->bigdirentries
) * sizeof(struct adfs_bigdirentry
);
151 offset
+= le32_to_cpu(bde
.bigdirobnameptr
);
153 dir_memcpy(dir
, offset
, obj
->name
, obj
->name_len
);
154 for (i
= 0; i
< obj
->name_len
; i
++)
155 if (obj
->name
[i
] == '/')
165 adfs_fplus_free(struct adfs_dir
*dir
)
169 for (i
= 0; i
< dir
->nr_buffers
; i
++)
174 struct adfs_dir_ops adfs_fplus_dir_ops
= {
175 .read
= adfs_fplus_read
,
176 .setpos
= adfs_fplus_setpos
,
177 .getnext
= adfs_fplus_getnext
,
178 .free
= adfs_fplus_free