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 */
58 NULL
, /* permission */
62 unsigned int adfs_val (unsigned char *p
, int len
)
79 static unsigned int adfs_filetype (unsigned int load
)
81 if ((load
& 0xfff00000) != 0xfff00000)
82 return (unsigned int) -1;
83 return (load
>> 8) & 0xfff;
86 static unsigned int adfs_time (unsigned int load
, unsigned int exec
)
88 unsigned int high
, low
;
90 /* Check for unstamped files. */
91 if ((load
& 0xfff00000) != 0xfff00000)
94 high
= ((load
<< 24) | (exec
>> 8));
97 /* Files dated pre 1970. */
98 if (high
< 0x336e996a)
103 /* Files dated post 2038 ish. */
104 if (high
> 0x31ffffff)
108 * (h256 % 100) = 56 h256 / 100 = 2
109 * 56 << 8 = 14336 2 * 256 = 512
114 return (((high
% 100) << 8) + low
) / 100 + (high
/ 100 << 8);
117 int adfs_readname (char *buf
, char *ptr
, int maxlen
)
120 while (*ptr
>= ' ' && maxlen
--) {
136 int adfs_dir_read_parent (struct inode
*inode
, struct buffer_head
**bhp
)
138 struct super_block
*sb
;
143 size
= 2048 >> sb
->s_blocksize_bits
;
145 for (i
= 0; i
< size
; i
++) {
148 block
= adfs_parent_bmap (inode
, i
);
150 bhp
[i
] = bread (sb
->s_dev
, block
, sb
->s_blocksize
);
152 adfs_error (sb
, "adfs_dir_read_parent",
153 "directory %lu with a hole at offset %d", inode
->i_ino
, i
);
154 if (!block
|| !bhp
[i
]) {
156 for (j
= i
- 1; j
>= 0; j
--)
164 int adfs_dir_read (struct inode
*inode
, struct buffer_head
**bhp
)
166 struct super_block
*sb
;
169 if (!inode
|| !S_ISDIR(inode
->i_mode
))
174 size
= inode
->i_size
>> sb
->s_blocksize_bits
;
176 for (i
= 0; i
< size
; i
++) {
179 block
= adfs_bmap (inode
, i
);
181 bhp
[i
] = bread (sb
->s_dev
, block
, sb
->s_blocksize
);
183 adfs_error (sb
, "adfs_dir_read",
184 "directory %lX,%lX with a hole at offset %d",
185 inode
->i_ino
, inode
->u
.adfs_i
.file_id
, i
);
186 if (!block
|| !bhp
[i
]) {
188 for (j
= i
- 1; j
>= 0; j
--)
196 int adfs_dir_check (struct inode
*inode
, struct buffer_head
**bhp
, int buffers
, union adfs_dirtail
*dtp
)
198 struct adfs_dirheader dh
;
199 union adfs_dirtail dt
;
201 memcpy (&dh
, bhp
[0]->b_data
, sizeof (dh
));
202 memcpy (&dt
, bhp
[3]->b_data
+ 471, sizeof(dt
));
204 if (memcmp (&dh
.startmasseq
, &dt
.new.endmasseq
, 5) ||
205 (memcmp (&dh
.startname
, "Nick", 4) &&
206 memcmp (&dh
.startname
, "Hugo", 4))) {
207 adfs_error (inode
->i_sb
, "adfs_check_dir",
208 "corrupted directory inode %lX,%lX",
209 inode
->i_ino
, inode
->u
.adfs_i
.file_id
);
217 void adfs_dir_free (struct buffer_head
**bhp
, int buffers
)
221 for (i
= buffers
- 1; i
>= 0; i
--)
225 /* convert a disk-based directory entry to a Linux ADFS directory entry */
227 adfs_dirent_to_idirent(struct adfs_idir_entry
*ide
, struct adfs_direntry
*de
)
229 ide
->name_len
= adfs_readname(ide
->name
, de
->dirobname
, ADFS_NAME_LEN
);
230 ide
->file_id
= adfs_val(de
->dirinddiscadd
, 3);
231 ide
->size
= adfs_val(de
->dirlen
, 4);
232 ide
->mode
= de
->newdiratts
;
233 ide
->mtime
= adfs_time(adfs_val(de
->dirload
, 4), adfs_val(de
->direxec
, 4));
234 ide
->filetype
= adfs_filetype(adfs_val(de
->dirload
, 4));
237 int adfs_dir_get (struct super_block
*sb
, struct buffer_head
**bhp
,
238 int buffers
, int pos
, unsigned long parent_object_id
,
239 struct adfs_idir_entry
*ide
)
241 struct adfs_direntry de
;
242 int thissize
, buffer
, offset
;
244 offset
= pos
& (sb
->s_blocksize
- 1);
245 buffer
= pos
>> sb
->s_blocksize_bits
;
247 if (buffer
> buffers
)
250 thissize
= sb
->s_blocksize
- offset
;
254 memcpy (&de
, bhp
[buffer
]->b_data
+ offset
, thissize
);
256 memcpy (((char *)&de
) + thissize
, bhp
[buffer
+ 1]->b_data
, 26 - thissize
);
258 if (!de
.dirobname
[0])
261 ide
->inode_no
= adfs_inode_generate (parent_object_id
, pos
);
262 adfs_dirent_to_idirent(ide
, &de
);
266 int adfs_dir_find_entry (struct super_block
*sb
, struct buffer_head
**bhp
,
267 int buffers
, unsigned int pos
,
268 struct adfs_idir_entry
*ide
)
270 struct adfs_direntry de
;
271 int offset
, buffer
, thissize
;
273 offset
= pos
& (sb
->s_blocksize
- 1);
274 buffer
= pos
>> sb
->s_blocksize_bits
;
276 if (buffer
> buffers
)
279 thissize
= sb
->s_blocksize
- offset
;
283 memcpy (&de
, bhp
[buffer
]->b_data
+ offset
, thissize
);
285 memcpy (((char *)&de
) + thissize
, bhp
[buffer
+ 1]->b_data
, 26 - thissize
);
287 if (!de
.dirobname
[0])
290 adfs_dirent_to_idirent(ide
, &de
);
294 static int adfs_readdir (struct file
*filp
, void *dirent
, filldir_t filldir
)
296 struct inode
*inode
= filp
->f_dentry
->d_inode
;
297 struct super_block
*sb
;
298 struct buffer_head
*bh
[4];
299 union adfs_dirtail dt
;
300 unsigned long parent_object_id
, dir_object_id
;
305 if (filp
->f_pos
> ADFS_NUM_DIR_ENTRIES
+ 2)
308 if (!(buffers
= adfs_dir_read (inode
, bh
))) {
309 adfs_error (sb
, "adfs_readdir", "unable to read directory");
313 if (adfs_dir_check (inode
, bh
, buffers
, &dt
)) {
314 adfs_dir_free (bh
, buffers
);
318 parent_object_id
= adfs_val (dt
.new.dirparent
, 3);
319 dir_object_id
= adfs_inode_objid (inode
);
321 if (filp
->f_pos
< 2) {
322 if (filp
->f_pos
< 1) {
323 if (filldir (dirent
, ".", 1, 0, inode
->i_ino
) < 0)
327 if (filldir (dirent
, "..", 2, 1,
328 adfs_inode_generate (parent_object_id
, 0)) < 0)
333 pos
= 5 + (filp
->f_pos
- 2) * 26;
334 while (filp
->f_pos
< 79) {
335 struct adfs_idir_entry ide
;
337 if (!adfs_dir_get (sb
, bh
, buffers
, pos
, dir_object_id
, &ide
))
340 if (filldir (dirent
, ide
.name
, ide
.name_len
, filp
->f_pos
, ide
.inode_no
) < 0)
345 adfs_dir_free (bh
, buffers
);