4 * Copyright (C) 1997 Russell King
7 #include <linux/errno.h>
9 #include <linux/adfs_fs.h>
10 #include <linux/sched.h>
11 #include <linux/stat.h>
13 static ssize_t
adfs_dirread (struct file
*filp
, char *buf
,
14 size_t siz
, loff_t
*ppos
)
19 static int adfs_readdir (struct file
*, void *, filldir_t
);
21 static struct file_operations adfs_dir_operations
= {
22 NULL
, /* lseek - default */
23 adfs_dirread
, /* read */
24 NULL
, /* write - bad */
25 adfs_readdir
, /* readdir */
26 NULL
, /* select - default */
29 NULL
, /* no special open code */
31 NULL
, /* no special release code */
32 file_fsync
, /* fsync */
34 NULL
, /* check_media_change */
39 * directories can handle most operations...
41 struct inode_operations adfs_dir_inode_operations
= {
42 &adfs_dir_operations
, /* default directory file-ops */
44 adfs_lookup
, /* lookup */
53 NULL
, /* follow link */
56 NULL
, /* write page */
57 NULL
, /* flush page */
59 NULL
, /* permission */
64 unsigned int adfs_val (unsigned char *p
, int len
)
81 static unsigned int adfs_filetype (unsigned int load
)
83 if ((load
& 0xfff00000) != 0xfff00000)
84 return (unsigned int) -1;
85 return (load
>> 8) & 0xfff;
88 static unsigned int adfs_time (unsigned int load
, unsigned int exec
)
90 unsigned int high
, low
;
92 /* Check for unstamped files. */
93 if ((load
& 0xfff00000) != 0xfff00000)
96 high
= ((load
<< 24) | (exec
>> 8));
99 /* Files dated pre 1970. */
100 if (high
< 0x336e996a)
105 /* Files dated post 2038 ish. */
106 if (high
> 0x31ffffff)
110 * (h256 % 100) = 56 h256 / 100 = 2
111 * 56 << 8 = 14336 2 * 256 = 512
116 return (((high
% 100) << 8) + low
) / 100 + (high
/ 100 << 8);
119 int adfs_readname (char *buf
, char *ptr
, int maxlen
)
122 while (*ptr
>= ' ' && maxlen
--) {
138 int adfs_dir_read_parent (struct inode
*inode
, struct buffer_head
**bhp
)
140 struct super_block
*sb
;
145 size
= 2048 >> sb
->s_blocksize_bits
;
147 for (i
= 0; i
< size
; i
++) {
150 block
= adfs_parent_bmap (inode
, i
);
152 bhp
[i
] = bread (sb
->s_dev
, block
, sb
->s_blocksize
);
154 adfs_error (sb
, "adfs_dir_read_parent",
155 "directory %lu with a hole at offset %d", inode
->i_ino
, i
);
156 if (!block
|| !bhp
[i
]) {
158 for (j
= i
- 1; j
>= 0; j
--)
166 int adfs_dir_read (struct inode
*inode
, struct buffer_head
**bhp
)
168 struct super_block
*sb
;
171 if (!inode
|| !S_ISDIR(inode
->i_mode
))
176 size
= inode
->i_size
>> sb
->s_blocksize_bits
;
178 for (i
= 0; i
< size
; i
++) {
181 block
= adfs_bmap (inode
, i
);
183 bhp
[i
] = bread (sb
->s_dev
, block
, sb
->s_blocksize
);
185 adfs_error (sb
, "adfs_dir_read",
186 "directory %lX,%lX with a hole at offset %d",
187 inode
->i_ino
, inode
->u
.adfs_i
.file_id
, i
);
188 if (!block
|| !bhp
[i
]) {
190 for (j
= i
- 1; j
>= 0; j
--)
198 int adfs_dir_check (struct inode
*inode
, struct buffer_head
**bhp
, int buffers
, union adfs_dirtail
*dtp
)
200 struct adfs_dirheader dh
;
201 union adfs_dirtail dt
;
203 memcpy (&dh
, bhp
[0]->b_data
, sizeof (dh
));
204 memcpy (&dt
, bhp
[3]->b_data
+ 471, sizeof(dt
));
206 if (memcmp (&dh
.startmasseq
, &dt
.new.endmasseq
, 5) ||
207 (memcmp (&dh
.startname
, "Nick", 4) &&
208 memcmp (&dh
.startname
, "Hugo", 4))) {
209 adfs_error (inode
->i_sb
, "adfs_check_dir",
210 "corrupted directory inode %lX,%lX",
211 inode
->i_ino
, inode
->u
.adfs_i
.file_id
);
219 void adfs_dir_free (struct buffer_head
**bhp
, int buffers
)
223 for (i
= buffers
- 1; i
>= 0; i
--)
227 /* convert a disk-based directory entry to a Linux ADFS directory entry */
229 adfs_dirent_to_idirent(struct adfs_idir_entry
*ide
, struct adfs_direntry
*de
)
231 ide
->name_len
= adfs_readname(ide
->name
, de
->dirobname
, ADFS_NAME_LEN
);
232 ide
->file_id
= adfs_val(de
->dirinddiscadd
, 3);
233 ide
->size
= adfs_val(de
->dirlen
, 4);
234 ide
->mode
= de
->newdiratts
;
235 ide
->mtime
= adfs_time(adfs_val(de
->dirload
, 4), adfs_val(de
->direxec
, 4));
236 ide
->filetype
= adfs_filetype(adfs_val(de
->dirload
, 4));
239 int adfs_dir_get (struct super_block
*sb
, struct buffer_head
**bhp
,
240 int buffers
, int pos
, unsigned long parent_object_id
,
241 struct adfs_idir_entry
*ide
)
243 struct adfs_direntry de
;
244 int thissize
, buffer
, offset
;
246 offset
= pos
& (sb
->s_blocksize
- 1);
247 buffer
= pos
>> sb
->s_blocksize_bits
;
249 if (buffer
> buffers
)
252 thissize
= sb
->s_blocksize
- offset
;
256 memcpy (&de
, bhp
[buffer
]->b_data
+ offset
, thissize
);
258 memcpy (((char *)&de
) + thissize
, bhp
[buffer
+ 1]->b_data
, 26 - thissize
);
260 if (!de
.dirobname
[0])
263 ide
->inode_no
= adfs_inode_generate (parent_object_id
, pos
);
264 adfs_dirent_to_idirent(ide
, &de
);
268 int adfs_dir_find_entry (struct super_block
*sb
, struct buffer_head
**bhp
,
269 int buffers
, unsigned int pos
,
270 struct adfs_idir_entry
*ide
)
272 struct adfs_direntry de
;
273 int offset
, buffer
, thissize
;
275 offset
= pos
& (sb
->s_blocksize
- 1);
276 buffer
= pos
>> sb
->s_blocksize_bits
;
278 if (buffer
> buffers
)
281 thissize
= sb
->s_blocksize
- offset
;
285 memcpy (&de
, bhp
[buffer
]->b_data
+ offset
, thissize
);
287 memcpy (((char *)&de
) + thissize
, bhp
[buffer
+ 1]->b_data
, 26 - thissize
);
289 if (!de
.dirobname
[0])
292 adfs_dirent_to_idirent(ide
, &de
);
296 static int adfs_readdir (struct file
*filp
, void *dirent
, filldir_t filldir
)
298 struct inode
*inode
= filp
->f_dentry
->d_inode
;
299 struct super_block
*sb
;
300 struct buffer_head
*bh
[4];
301 union adfs_dirtail dt
;
302 unsigned long parent_object_id
, dir_object_id
;
307 if (filp
->f_pos
> ADFS_NUM_DIR_ENTRIES
+ 2)
310 if (!(buffers
= adfs_dir_read (inode
, bh
))) {
311 adfs_error (sb
, "adfs_readdir", "unable to read directory");
315 if (adfs_dir_check (inode
, bh
, buffers
, &dt
)) {
316 adfs_dir_free (bh
, buffers
);
320 parent_object_id
= adfs_val (dt
.new.dirparent
, 3);
321 dir_object_id
= adfs_inode_objid (inode
);
323 if (filp
->f_pos
< 2) {
324 if (filp
->f_pos
< 1) {
325 if (filldir (dirent
, ".", 1, 0, inode
->i_ino
) < 0)
329 if (filldir (dirent
, "..", 2, 1,
330 adfs_inode_generate (parent_object_id
, 0)) < 0)
335 pos
= 5 + (filp
->f_pos
- 2) * 26;
336 while (filp
->f_pos
< 79) {
337 struct adfs_idir_entry ide
;
339 if (!adfs_dir_get (sb
, bh
, buffers
, pos
, dir_object_id
, &ide
))
342 if (filldir (dirent
, ide
.name
, ide
.name_len
, filp
->f_pos
, ide
.inode_no
) < 0)
347 adfs_dir_free (bh
, buffers
);