patch-2.1.80 linux/fs/adfs/dir.c
Next file: linux/fs/adfs/file.c
Previous file: linux/fs/adfs/Makefile
Back to the patch index
Back to the overall index
- Lines: 329
- Date:
Tue Jan 20 16:44:58 1998
- Orig file:
v2.1.79/linux/fs/adfs/dir.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.1.79/linux/fs/adfs/dir.c linux/fs/adfs/dir.c
@@ -0,0 +1,328 @@
+/*
+ * linux/fs/adfs/dir.c
+ *
+ * Copyright (C) 1997 Russell King
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/adfs_fs.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+
+static ssize_t adfs_dirread (struct file *filp, char *buf,
+ size_t siz, loff_t *ppos)
+{
+ return -EISDIR;
+}
+
+static int adfs_readdir (struct file *, void *, filldir_t);
+
+static struct file_operations adfs_dir_operations = {
+ NULL, /* lseek - default */
+ adfs_dirread, /* read */
+ NULL, /* write - bad */
+ adfs_readdir, /* readdir */
+ NULL, /* select - default */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ NULL, /* no special open code */
+ NULL, /* no special release code */
+ file_fsync, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL /* revalidate */
+};
+
+/*
+ * directories can handle most operations...
+ */
+struct inode_operations adfs_dir_inode_operations = {
+ &adfs_dir_operations, /* default directory file-ops */
+ NULL, /* create */
+ adfs_lookup, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* read link */
+ NULL, /* follow link */
+ NULL, /* read page */
+ NULL, /* write page */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL, /* permission */
+ NULL /* smap */
+};
+
+unsigned int adfs_val (unsigned char *p, int len)
+{
+ unsigned int val = 0;
+
+ switch (len) {
+ case 4:
+ val |= p[3] << 24;
+ case 3:
+ val |= p[2] << 16;
+ case 2:
+ val |= p[1] << 8;
+ default:
+ val |= p[0];
+ }
+ return val;
+}
+
+static unsigned int adfs_time (unsigned int load, unsigned int exec)
+{
+ unsigned int high, low;
+
+ high = ((load << 24) | (exec >> 8)) - 0x336e996a;
+ low = exec & 255;
+
+ /* 65537 = h256,l1
+ * (h256 % 100) = 56 h256 / 100 = 2
+ * 56 << 8 = 14336 2 * 256 = 512
+ * + l1 = 14337
+ * / 100 = 143
+ * + 512 = 655
+ */
+ return (((high % 100) << 8) + low) / 100 + (high / 100 << 8);
+}
+
+int adfs_readname (char *buf, char *ptr, int maxlen)
+{
+ int size = 0;
+ while (*ptr >= ' ' && maxlen--) {
+ switch (*ptr) {
+ case '/':
+ *buf++ = '.';
+ break;
+ default:
+ *buf++ = *ptr;
+ break;
+ }
+ ptr++;
+ size ++;
+ }
+ *buf = '\0';
+ return size;
+}
+
+int adfs_dir_read_parent (struct inode *inode, struct buffer_head **bhp)
+{
+ struct super_block *sb;
+ int i, size;
+
+ if (!inode)
+ return 0;
+
+ sb = inode->i_sb;
+
+ size = 2048 >> sb->s_blocksize_bits;
+
+ for (i = 0; i < size; i++) {
+ int block;
+
+ block = adfs_parent_bmap (inode, i);
+ if (block)
+ bhp[i] = bread (sb->s_dev, block, sb->s_blocksize);
+ else
+ adfs_error (sb, "adfs_dir_read_parent",
+ "directory %lu with a hole at offset %d", inode->i_ino, i);
+ if (!block || !bhp[i]) {
+ int j;
+ for (j = i - 1; j >= 0; j--)
+ brelse (bhp[j]);
+ return 0;
+ }
+ }
+ return i;
+}
+
+int adfs_dir_read (struct inode *inode, struct buffer_head **bhp)
+{
+ struct super_block *sb;
+ int i, size;
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ return 0;
+
+ sb = inode->i_sb;
+
+ size = inode->i_size >> sb->s_blocksize_bits;
+
+ for (i = 0; i < size; i++) {
+ int block;
+
+ block = adfs_bmap (inode, i);
+ if (block)
+ bhp[i] = bread (sb->s_dev, block, sb->s_blocksize);
+ else
+ adfs_error (sb, "adfs_dir_read",
+ "directory %lX,%lX with a hole at offset %d",
+ inode->i_ino, inode->u.adfs_i.file_id, i);
+ if (!block || !bhp[i]) {
+ int j;
+ for (j = i - 1; j >= 0; j--)
+ brelse (bhp[j]);
+ return 0;
+ }
+ }
+ return i;
+}
+
+int adfs_dir_check (struct inode *inode, struct buffer_head **bhp, int buffers, union adfs_dirtail *dtp)
+{
+ struct adfs_dirheader dh;
+ union adfs_dirtail dt;
+
+ memcpy (&dh, bhp[0]->b_data, sizeof (dh));
+ memcpy (&dt, bhp[3]->b_data + 471, sizeof(dt));
+
+ if (memcmp (&dh.startmasseq, &dt.new.endmasseq, 5) ||
+ (memcmp (&dh.startname, "Nick", 4) &&
+ memcmp (&dh.startname, "Hugo", 4))) {
+ adfs_error (inode->i_sb, "adfs_check_dir",
+ "corrupted directory inode %lX,%lX",
+ inode->i_ino, inode->u.adfs_i.file_id);
+ return 1;
+ }
+ if (dtp)
+ *dtp = dt;
+ return 0;
+}
+
+void adfs_dir_free (struct buffer_head **bhp, int buffers)
+{
+ int i;
+
+ for (i = buffers - 1; i >= 0; i--)
+ brelse (bhp[i]);
+}
+
+int adfs_dir_get (struct super_block *sb, struct buffer_head **bhp,
+ int buffers, int pos, unsigned long parent_object_id,
+ struct adfs_idir_entry *ide)
+{
+ struct adfs_direntry de;
+ int thissize, buffer, offset;
+
+ offset = pos & (sb->s_blocksize - 1);
+ buffer = pos >> sb->s_blocksize_bits;
+
+ if (buffer > buffers)
+ return 0;
+
+ thissize = sb->s_blocksize - offset;
+ if (thissize > 26)
+ thissize = 26;
+
+ memcpy (&de, bhp[buffer]->b_data + offset, thissize);
+ if (thissize != 26)
+ memcpy (((char *)&de) + thissize, bhp[buffer + 1]->b_data, 26 - thissize);
+
+ if (!de.dirobname[0])
+ return 0;
+
+ ide->name_len = adfs_readname (ide->name, de.dirobname, ADFS_NAME_LEN);
+ ide->inode_no = adfs_inode_generate (parent_object_id, pos);
+ ide->file_id = adfs_val (de.dirinddiscadd, 3);
+ ide->size = adfs_val (de.dirlen, 4);
+ ide->mode = de.newdiratts;
+ ide->mtime = adfs_time (adfs_val (de.dirload, 4), adfs_val (de.direxec, 4));
+ ide->filetype = (adfs_val (de.dirload, 4) >> 8) & 0xfff;
+ return 1;
+}
+
+int adfs_dir_find_entry (struct super_block *sb, struct buffer_head **bhp,
+ int buffers, unsigned int pos,
+ struct adfs_idir_entry *ide)
+{
+ struct adfs_direntry de;
+ int offset, buffer, thissize;
+
+ offset = pos & (sb->s_blocksize - 1);
+ buffer = pos >> sb->s_blocksize_bits;
+
+ if (buffer > buffers)
+ return 0;
+
+ thissize = sb->s_blocksize - offset;
+ if (thissize > 26)
+ thissize = 26;
+
+ memcpy (&de, bhp[buffer]->b_data + offset, thissize);
+ if (thissize != 26)
+ memcpy (((char *)&de) + thissize, bhp[buffer + 1]->b_data, 26 - thissize);
+
+ if (!de.dirobname[0])
+ return 0;
+
+ ide->name_len = adfs_readname (ide->name, de.dirobname, ADFS_NAME_LEN);
+ ide->size = adfs_val (de.dirlen, 4);
+ ide->mode = de.newdiratts;
+ ide->file_id = adfs_val (de.dirinddiscadd, 3);
+ ide->mtime = adfs_time (adfs_val (de.dirload, 4), adfs_val (de.direxec, 4));
+ ide->filetype = (adfs_val (de.dirload, 4) >> 8) & 0xfff;
+ return 1;
+}
+
+static int adfs_readdir (struct file *filp, void *dirent, filldir_t filldir)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct super_block *sb;
+ struct buffer_head *bh[4];
+ union adfs_dirtail dt;
+ unsigned long parent_object_id, dir_object_id;
+ int buffers, pos;
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ return -EBADF;
+ sb = inode->i_sb;
+
+ if (filp->f_pos > ADFS_NUM_DIR_ENTRIES + 2)
+ return -ENOENT;
+
+ if (!(buffers = adfs_dir_read (inode, bh))) {
+ adfs_error (sb, "adfs_readdir", "unable to read directory");
+ return -EINVAL;
+ }
+
+ if (adfs_dir_check (inode, bh, buffers, &dt)) {
+ adfs_dir_free (bh, buffers);
+ return -ENOENT;
+ }
+
+ parent_object_id = adfs_val (dt.new.dirparent, 3);
+ dir_object_id = adfs_inode_objid (inode);
+
+ if (filp->f_pos < 2) {
+ if (filp->f_pos < 1) {
+ if (filldir (dirent, ".", 1, 0, inode->i_ino) < 0)
+ return 0;
+ filp->f_pos ++;
+ }
+ if (filldir (dirent, "..", 2, 1,
+ adfs_inode_generate (parent_object_id, 0)) < 0)
+ return 0;
+ filp->f_pos ++;
+ }
+
+ pos = 5 + (filp->f_pos - 2) * 26;
+ while (filp->f_pos < 79) {
+ struct adfs_idir_entry ide;
+
+ if (!adfs_dir_get (sb, bh, buffers, pos, dir_object_id, &ide))
+ break;
+
+ if (filldir (dirent, ide.name, ide.name_len, filp->f_pos, ide.inode_no) < 0)
+ return 0;
+ filp->f_pos ++;
+ pos += 26;
+ }
+ adfs_dir_free (bh, buffers);
+ return 0;
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov