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/buffer_head.h>
12 #include "dir_fplus.h"
15 adfs_fplus_read(struct super_block
*sb
, unsigned int id
, unsigned int sz
, struct adfs_dir
*dir
)
17 struct adfs_bigdirheader
*h
;
18 struct adfs_bigdirtail
*t
;
20 unsigned int blk
, size
;
25 block
= __adfs_block_map(sb
, id
, 0);
27 adfs_error(sb
, "dir object %X has a hole at offset 0", id
);
31 dir
->bh
[0] = sb_bread(sb
, block
);
36 h
= (struct adfs_bigdirheader
*)dir
->bh
[0]->b_data
;
37 size
= le32_to_cpu(h
->bigdirsize
);
39 printk(KERN_WARNING
"adfs: adfs_fplus_read: directory header size\n"
40 " does not match directory size\n");
43 if (h
->bigdirversion
[0] != 0 || h
->bigdirversion
[1] != 0 ||
44 h
->bigdirversion
[2] != 0 || size
& 2047 ||
45 h
->bigdirstartname
!= cpu_to_le32(BIGDIRSTARTNAME
))
48 size
>>= sb
->s_blocksize_bits
;
49 for (blk
= 1; blk
< size
; blk
++) {
50 block
= __adfs_block_map(sb
, id
, blk
);
52 adfs_error(sb
, "dir object %X has a hole at offset %d", id
, blk
);
56 dir
->bh
[blk
] = sb_bread(sb
, block
);
59 dir
->nr_buffers
= blk
;
62 t
= (struct adfs_bigdirtail
*)(dir
->bh
[size
- 1]->b_data
+ (sb
->s_blocksize
- 8));
64 if (t
->bigdirendname
!= cpu_to_le32(BIGDIRENDNAME
) ||
65 t
->bigdirendmasseq
!= h
->startmasseq
||
66 t
->reserved
[0] != 0 || t
->reserved
[1] != 0)
69 dir
->parent_id
= le32_to_cpu(h
->bigdirparent
);
73 for (i
= 0; i
< dir
->nr_buffers
; i
++)
80 adfs_fplus_setpos(struct adfs_dir
*dir
, unsigned int fpos
)
82 struct adfs_bigdirheader
*h
= (struct adfs_bigdirheader
*)dir
->bh
[0]->b_data
;
85 if (fpos
<= le32_to_cpu(h
->bigdirentries
)) {
94 dir_memcpy(struct adfs_dir
*dir
, unsigned int offset
, void *to
, int len
)
96 struct super_block
*sb
= dir
->sb
;
97 unsigned int buffer
, partial
, remainder
;
99 buffer
= offset
>> sb
->s_blocksize_bits
;
100 offset
&= sb
->s_blocksize
- 1;
102 partial
= sb
->s_blocksize
- offset
;
105 memcpy(to
, dir
->bh
[buffer
]->b_data
+ offset
, len
);
107 char *c
= (char *)to
;
109 remainder
= len
- partial
;
111 memcpy(c
, dir
->bh
[buffer
]->b_data
+ offset
, partial
);
112 memcpy(c
+ partial
, dir
->bh
[buffer
+ 1]->b_data
, remainder
);
117 adfs_fplus_getnext(struct adfs_dir
*dir
, struct object_info
*obj
)
119 struct adfs_bigdirheader
*h
= (struct adfs_bigdirheader
*)dir
->bh
[0]->b_data
;
120 struct adfs_bigdirentry bde
;
122 int i
, ret
= -ENOENT
;
124 if (dir
->pos
>= le32_to_cpu(h
->bigdirentries
))
127 offset
= offsetof(struct adfs_bigdirheader
, bigdirname
);
128 offset
+= ((le32_to_cpu(h
->bigdirnamelen
) + 4) & ~3);
129 offset
+= dir
->pos
* sizeof(struct adfs_bigdirentry
);
131 dir_memcpy(dir
, offset
, &bde
, sizeof(struct adfs_bigdirentry
));
133 obj
->loadaddr
= le32_to_cpu(bde
.bigdirload
);
134 obj
->execaddr
= le32_to_cpu(bde
.bigdirexec
);
135 obj
->size
= le32_to_cpu(bde
.bigdirlen
);
136 obj
->file_id
= le32_to_cpu(bde
.bigdirindaddr
);
137 obj
->attr
= le32_to_cpu(bde
.bigdirattr
);
138 obj
->name_len
= le32_to_cpu(bde
.bigdirobnamelen
);
140 offset
= offsetof(struct adfs_bigdirheader
, bigdirname
);
141 offset
+= ((le32_to_cpu(h
->bigdirnamelen
) + 4) & ~3);
142 offset
+= le32_to_cpu(h
->bigdirentries
) * sizeof(struct adfs_bigdirentry
);
143 offset
+= le32_to_cpu(bde
.bigdirobnameptr
);
145 dir_memcpy(dir
, offset
, obj
->name
, obj
->name_len
);
146 for (i
= 0; i
< obj
->name_len
; i
++)
147 if (obj
->name
[i
] == '/')
157 adfs_fplus_sync(struct adfs_dir
*dir
)
162 for (i
= dir
->nr_buffers
- 1; i
>= 0; i
--) {
163 struct buffer_head
*bh
= dir
->bh
[i
];
164 sync_dirty_buffer(bh
);
165 if (buffer_req(bh
) && !buffer_uptodate(bh
))
173 adfs_fplus_free(struct adfs_dir
*dir
)
177 for (i
= 0; i
< dir
->nr_buffers
; i
++)
182 struct adfs_dir_ops adfs_fplus_dir_ops
= {
183 .read
= adfs_fplus_read
,
184 .setpos
= adfs_fplus_setpos
,
185 .getnext
= adfs_fplus_getnext
,
186 .sync
= adfs_fplus_sync
,
187 .free
= adfs_fplus_free