Import 2.2.7
[davej-history.git] / fs / adfs / dir.c
blobac81954d7b6c3d81e690be7ee46ac7356ad9fca2
1 /*
2 * linux/fs/adfs/dir.c
4 * Copyright (C) 1997 Russell King
5 */
7 #include <linux/errno.h>
8 #include <linux/fs.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)
16 return -EISDIR;
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 */
27 NULL, /* ioctl */
28 NULL, /* mmap */
29 NULL, /* no special open code */
30 NULL, /* flush */
31 NULL, /* no special release code */
32 file_fsync, /* fsync */
33 NULL, /* fasync */
34 NULL, /* check_media_change */
35 NULL /* revalidate */
39 * directories can handle most operations...
41 struct inode_operations adfs_dir_inode_operations = {
42 &adfs_dir_operations, /* default directory file-ops */
43 NULL, /* create */
44 adfs_lookup, /* lookup */
45 NULL, /* link */
46 NULL, /* unlink */
47 NULL, /* symlink */
48 NULL, /* mkdir */
49 NULL, /* rmdir */
50 NULL, /* mknod */
51 NULL, /* rename */
52 NULL, /* read link */
53 NULL, /* follow link */
54 NULL, /* read page */
55 NULL, /* write page */
56 NULL, /* bmap */
57 NULL, /* truncate */
58 NULL, /* permission */
59 NULL /* smap */
62 unsigned int adfs_val (unsigned char *p, int len)
64 unsigned int val = 0;
66 switch (len) {
67 case 4:
68 val |= p[3] << 24;
69 case 3:
70 val |= p[2] << 16;
71 case 2:
72 val |= p[1] << 8;
73 default:
74 val |= p[0];
76 return val;
79 static unsigned int adfs_time (unsigned int load, unsigned int exec)
81 unsigned int high, low;
83 high = ((load << 24) | (exec >> 8)) - 0x336e996a;
84 low = exec & 255;
86 /* 65537 = h256,l1
87 * (h256 % 100) = 56 h256 / 100 = 2
88 * 56 << 8 = 14336 2 * 256 = 512
89 * + l1 = 14337
90 * / 100 = 143
91 * + 512 = 655
93 return (((high % 100) << 8) + low) / 100 + (high / 100 << 8);
96 int adfs_readname (char *buf, char *ptr, int maxlen)
98 int size = 0;
99 while (*ptr >= ' ' && maxlen--) {
100 switch (*ptr) {
101 case '/':
102 *buf++ = '.';
103 break;
104 default:
105 *buf++ = *ptr;
106 break;
108 ptr++;
109 size ++;
111 *buf = '\0';
112 return size;
115 int adfs_dir_read_parent (struct inode *inode, struct buffer_head **bhp)
117 struct super_block *sb;
118 int i, size;
120 if (!inode)
121 return 0;
123 sb = inode->i_sb;
125 size = 2048 >> sb->s_blocksize_bits;
127 for (i = 0; i < size; i++) {
128 int block;
130 block = adfs_parent_bmap (inode, i);
131 if (block)
132 bhp[i] = bread (sb->s_dev, block, sb->s_blocksize);
133 else
134 adfs_error (sb, "adfs_dir_read_parent",
135 "directory %lu with a hole at offset %d", inode->i_ino, i);
136 if (!block || !bhp[i]) {
137 int j;
138 for (j = i - 1; j >= 0; j--)
139 brelse (bhp[j]);
140 return 0;
143 return i;
146 int adfs_dir_read (struct inode *inode, struct buffer_head **bhp)
148 struct super_block *sb;
149 int i, size;
151 if (!inode || !S_ISDIR(inode->i_mode))
152 return 0;
154 sb = inode->i_sb;
156 size = inode->i_size >> sb->s_blocksize_bits;
158 for (i = 0; i < size; i++) {
159 int block;
161 block = adfs_bmap (inode, i);
162 if (block)
163 bhp[i] = bread (sb->s_dev, block, sb->s_blocksize);
164 else
165 adfs_error (sb, "adfs_dir_read",
166 "directory %lX,%lX with a hole at offset %d",
167 inode->i_ino, inode->u.adfs_i.file_id, i);
168 if (!block || !bhp[i]) {
169 int j;
170 for (j = i - 1; j >= 0; j--)
171 brelse (bhp[j]);
172 return 0;
175 return i;
178 int adfs_dir_check (struct inode *inode, struct buffer_head **bhp, int buffers, union adfs_dirtail *dtp)
180 struct adfs_dirheader dh;
181 union adfs_dirtail dt;
183 memcpy (&dh, bhp[0]->b_data, sizeof (dh));
184 memcpy (&dt, bhp[3]->b_data + 471, sizeof(dt));
186 if (memcmp (&dh.startmasseq, &dt.new.endmasseq, 5) ||
187 (memcmp (&dh.startname, "Nick", 4) &&
188 memcmp (&dh.startname, "Hugo", 4))) {
189 adfs_error (inode->i_sb, "adfs_check_dir",
190 "corrupted directory inode %lX,%lX",
191 inode->i_ino, inode->u.adfs_i.file_id);
192 return 1;
194 if (dtp)
195 *dtp = dt;
196 return 0;
199 void adfs_dir_free (struct buffer_head **bhp, int buffers)
201 int i;
203 for (i = buffers - 1; i >= 0; i--)
204 brelse (bhp[i]);
207 int adfs_dir_get (struct super_block *sb, struct buffer_head **bhp,
208 int buffers, int pos, unsigned long parent_object_id,
209 struct adfs_idir_entry *ide)
211 struct adfs_direntry de;
212 int thissize, buffer, offset;
214 offset = pos & (sb->s_blocksize - 1);
215 buffer = pos >> sb->s_blocksize_bits;
217 if (buffer > buffers)
218 return 0;
220 thissize = sb->s_blocksize - offset;
221 if (thissize > 26)
222 thissize = 26;
224 memcpy (&de, bhp[buffer]->b_data + offset, thissize);
225 if (thissize != 26)
226 memcpy (((char *)&de) + thissize, bhp[buffer + 1]->b_data, 26 - thissize);
228 if (!de.dirobname[0])
229 return 0;
231 ide->name_len = adfs_readname (ide->name, de.dirobname, ADFS_NAME_LEN);
232 ide->inode_no = adfs_inode_generate (parent_object_id, pos);
233 ide->file_id = adfs_val (de.dirinddiscadd, 3);
234 ide->size = adfs_val (de.dirlen, 4);
235 ide->mode = de.newdiratts;
236 ide->mtime = adfs_time (adfs_val (de.dirload, 4), adfs_val (de.direxec, 4));
237 ide->filetype = (adfs_val (de.dirload, 4) >> 8) & 0xfff;
238 return 1;
241 int adfs_dir_find_entry (struct super_block *sb, struct buffer_head **bhp,
242 int buffers, unsigned int pos,
243 struct adfs_idir_entry *ide)
245 struct adfs_direntry de;
246 int offset, buffer, thissize;
248 offset = pos & (sb->s_blocksize - 1);
249 buffer = pos >> sb->s_blocksize_bits;
251 if (buffer > buffers)
252 return 0;
254 thissize = sb->s_blocksize - offset;
255 if (thissize > 26)
256 thissize = 26;
258 memcpy (&de, bhp[buffer]->b_data + offset, thissize);
259 if (thissize != 26)
260 memcpy (((char *)&de) + thissize, bhp[buffer + 1]->b_data, 26 - thissize);
262 if (!de.dirobname[0])
263 return 0;
265 ide->name_len = adfs_readname (ide->name, de.dirobname, ADFS_NAME_LEN);
266 ide->size = adfs_val (de.dirlen, 4);
267 ide->mode = de.newdiratts;
268 ide->file_id = adfs_val (de.dirinddiscadd, 3);
269 ide->mtime = adfs_time (adfs_val (de.dirload, 4), adfs_val (de.direxec, 4));
270 ide->filetype = (adfs_val (de.dirload, 4) >> 8) & 0xfff;
271 return 1;
274 static int adfs_readdir (struct file *filp, void *dirent, filldir_t filldir)
276 struct inode *inode = filp->f_dentry->d_inode;
277 struct super_block *sb;
278 struct buffer_head *bh[4];
279 union adfs_dirtail dt;
280 unsigned long parent_object_id, dir_object_id;
281 int buffers, pos;
283 sb = inode->i_sb;
285 if (filp->f_pos > ADFS_NUM_DIR_ENTRIES + 2)
286 return -ENOENT;
288 if (!(buffers = adfs_dir_read (inode, bh))) {
289 adfs_error (sb, "adfs_readdir", "unable to read directory");
290 return -EINVAL;
293 if (adfs_dir_check (inode, bh, buffers, &dt)) {
294 adfs_dir_free (bh, buffers);
295 return -ENOENT;
298 parent_object_id = adfs_val (dt.new.dirparent, 3);
299 dir_object_id = adfs_inode_objid (inode);
301 if (filp->f_pos < 2) {
302 if (filp->f_pos < 1) {
303 if (filldir (dirent, ".", 1, 0, inode->i_ino) < 0)
304 return 0;
305 filp->f_pos ++;
307 if (filldir (dirent, "..", 2, 1,
308 adfs_inode_generate (parent_object_id, 0)) < 0)
309 return 0;
310 filp->f_pos ++;
313 pos = 5 + (filp->f_pos - 2) * 26;
314 while (filp->f_pos < 79) {
315 struct adfs_idir_entry ide;
317 if (!adfs_dir_get (sb, bh, buffers, pos, dir_object_id, &ide))
318 break;
320 if (filldir (dirent, ide.name, ide.name_len, filp->f_pos, ide.inode_no) < 0)
321 return 0;
322 filp->f_pos ++;
323 pos += 26;
325 adfs_dir_free (bh, buffers);
326 return 0;