patch-1.3.99 linux/fs/affs/dir.c
Next file: linux/fs/affs/file.c
Previous file: linux/fs/affs/bitmap.c
Back to the patch index
Back to the overall index
- Lines: 286
- Date:
Mon May 6 14:36:24 1996
- Orig file:
v1.3.98/linux/fs/affs/dir.c
- Orig date:
Tue Apr 23 13:57:11 1996
diff -u --recursive --new-file v1.3.98/linux/fs/affs/dir.c linux/fs/affs/dir.c
@@ -1,6 +1,8 @@
/*
* linux/fs/affs/dir.c
*
+ * (c) 1996 Hans-Joachim Widmaier - Modifications for larger blocks
+ * and hard links.
* (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
*
* (C) 1992 Eric Youngdale Modified for ISO9660 filesystem.
@@ -8,25 +10,25 @@
* (C) 1991 Linus Torvalds - minix filesystem
*
* affs directory handling functions
+ *
*/
-#include <linux/errno.h>
-
#include <asm/segment.h>
-
+#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/affs_fs.h>
#include <linux/kernel.h>
#include <linux/affs_fs.h>
#include <linux/stat.h>
#include <linux/string.h>
-#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/amigaffs.h>
static int affs_readdir(struct inode *, struct file *, void *, filldir_t);
+static int affs_dir_read(struct inode * inode, struct file * filp, char * buf, int count);
-struct file_operations affs_dir_operations = {
+static struct file_operations affs_dir_operations = {
NULL, /* lseek - default */
- NULL, /* read */
+ affs_dir_read, /* read */
NULL, /* write - bad */
affs_readdir, /* readdir */
NULL, /* select - default */
@@ -34,7 +36,7 @@
NULL, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
- NULL /* fsync */
+ file_fsync /* default fsync */
};
/*
@@ -42,109 +44,153 @@
*/
struct inode_operations affs_dir_inode_operations = {
&affs_dir_operations, /* default directory file-ops */
- NULL, /* create */
+ affs_create, /* create */
affs_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
+ affs_link, /* link */
+ affs_unlink, /* unlink */
+ affs_symlink, /* symlink */
+ affs_mkdir, /* mkdir */
+ affs_rmdir, /* rmdir */
NULL, /* mknod */
- NULL, /* rename */
+ affs_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
NULL, /* bmap */
- NULL, /* truncate */
- NULL /* permission */
+ affs_dir_truncate, /* truncate */
+ NULL /* permissions */
};
-/* This is used to speed up lookup. Without this we would need to
-make a linear search of the directory to find the file that the
-directory read just returned. This is a single element cache. */
-
-/* struct lookup_cache cache = {0,}; */
+static int
+affs_dir_read(struct inode * inode, struct file * filp, char * buf, int count)
+{
+ return -EISDIR;
+}
-static int affs_readdir(struct inode * inode, struct file * filp,
- void * dirent, filldir_t filldir)
+static int
+affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t filldir)
{
- int i, j, chain_pos, hash_pos, reclen, ino;
+ int j, namelen;
+ LONG i;
+ ULONG hash_pos;
+ ULONG chain_pos;
+ unsigned long ino;
+ unsigned long old;
+ int stored;
char *name;
struct buffer_head *dir_bh;
struct buffer_head *fh_bh;
- void *dir_data;
- void *fh_data;
+ struct inode *dir;
-#ifdef DEBUG
- printk ("AFFS: readdir: inode=%d f_pos=%d\n",
- inode->i_ino, filp->f_pos);
-#endif
+ pr_debug("AFFS: readdir(ino=%ld,f_pos=%lu)\n",inode->i_ino,filp->f_pos);
+
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
- while ((unsigned long)filp->f_pos < 2) {
- if (filp->f_pos == 0) {
- if (filldir (dirent, ".", 1, filp->f_pos, inode->i_ino) < 0)
- return 0;
- } else {
- i = affs_parent_ino (inode);
- if (filldir (dirent, "..", 2, filp->f_pos, i) < 0)
- return 0;
+ stored = 0;
+ dir_bh = NULL;
+ fh_bh = NULL;
+ dir = NULL;
+ old = filp->f_pos & 0x80000000;
+ filp->f_pos &= 0x7FFFFFFF;
+
+ if (filp->f_pos == 0) {
+ filp->private_data = (void *)0;
+ if (filldir(dirent,".",1,filp->f_pos,inode->i_ino) < 0) {
+ return 0;
}
- filp->f_pos++;
+ ++filp->f_pos;
+ stored++;
}
- /* No caching here. I've got 16 megs why should I care? :-) */
- chain_pos = (filp->f_pos - 2) & 0xffff;
- if (chain_pos == 0xffff)
- return 0;
- hash_pos = (filp->f_pos - 2) >> 16;
-#ifdef DEBUG
- printk ("AFFS: hash_pos=%d chain_pos=%d\n", hash_pos, chain_pos);
-#endif
- if (!(dir_bh = affs_pread(inode, inode->i_ino, &dir_data)))
- return 0;
- /* HASH_POS should already be on a used entry unless it is
- the first read of the directory. Will this break the
- dirtell thing somehow? */
- i = affs_find_next_hash_entry (AFFS_I2BSIZE (inode), dir_data,
- &hash_pos);
- j = chain_pos;
- for (;;) {
- if (i <= 0) {
-#ifdef DEBUG
- printk ("AFFS: bad f_pos in readdir\n");
-#endif
- brelse (dir_bh);
- return 0;
+ if (filp->f_pos == 1) {
+ if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode)) < 0) {
+ filp->f_pos |= 0x80000000;
+ return stored;
}
- ino = i;
- if (!(fh_bh = affs_pread (inode, i, &fh_data))) {
- brelse (dir_bh);
- return 0;
+ filp->f_pos = 2;
+ stored++;
+ }
+
+ /* Read original if this is a link */
+ ino = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino;
+ if (!(dir = iget(inode->i_sb,ino)))
+ return stored;
+
+ chain_pos = (filp->f_pos - 2) & 0xffff;
+ hash_pos = (filp->f_pos - 2) >> 16;
+ if (chain_pos == 0xffff) {
+ printk("AFFS: more than 65535 entries in chain\n");
+ chain_pos = 0;
+ hash_pos++;
+ filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
+ }
+ if (!(dir_bh = affs_bread(inode->i_dev,ino,AFFS_I2BSIZE(inode))))
+ goto readdir_done;
+
+ while (!stored || !old) {
+ while (hash_pos < AFFS_I2HSIZE(inode) &&
+ !((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos])
+ hash_pos++;
+ if (hash_pos >= AFFS_I2HSIZE(inode))
+ goto readdir_done;
+
+ i = htonl(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]);
+ j = chain_pos;
+ /* If the directory hasn't changed since the last call to readdir(),
+ * we can jump directly to where we left off.
+ */
+ if (filp->private_data && filp->f_version == dir->i_version) {
+ i = (ULONG)filp->private_data;
+ j = 0;
+ pd_debug("AFFS: readdir() left off=%lu\n",i);
}
- i = affs_get_fh_hash_link (AFFS_I2BSIZE (inode), fh_data);
- if (j == 0) {
- j = 1;
- if (i <= 0) {
- hash_pos++;
- i = affs_find_next_hash_entry (AFFS_I2BSIZE (inode),
- dir_data, &hash_pos);
- if (i <= 0)
- chain_pos = 0xffff;
- else
- chain_pos = 0;
- } else
- chain_pos++;
- reclen = affs_get_file_name (AFFS_I2BSIZE (inode),
- fh_data, &name);
- if (filldir (dirent, name, reclen, filp->f_pos, ino) < 0) {
- brelse (fh_bh);
- brelse (dir_bh);
- return 0;
+ filp->f_version = dir->i_version;
+ pd_debug("AFFS: hash_pos=%lu chain_pos=%lu\n", hash_pos, chain_pos);
+ while (i) {
+ if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) {
+ printk("AFFS: readdir: Can't get block %d\n",i);
+ goto readdir_done;
}
- filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
+ ino = i;
+ i = htonl(FILE_END(fh_bh->b_data,inode)->hash_chain);
+ if (j == 0)
+ break;
+ affs_brelse(fh_bh);
+ fh_bh = NULL;
+ j--;
+ }
+ if (fh_bh) {
+ namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name);
+ pr_debug("AFFS: readdir(): filldir(..,\"%.*s\",ino=%lu), i=%lu\n",namelen,name,ino,i);
+ filp->private_data = (void *)ino;
+ if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0)
+ goto readdir_done;
+ filp->private_data = (void *)i;
+ affs_brelse(fh_bh);
+ fh_bh = NULL;
+ stored++;
}
- brelse (fh_bh);
- j--;
+ if (i == 0) {
+ hash_pos++;
+ chain_pos = 0;
+ } else
+ chain_pos++;
+ filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
}
+
+readdir_done:
+ filp->f_pos |= old;
+ affs_brelse(dir_bh);
+ affs_brelse(fh_bh);
+ iput(dir);
+ pr_debug("AFFS: readdir()=%d\n",stored);
+ return stored;
+}
+
+void
+affs_dir_truncate(struct inode *inode)
+{
+ printk("AFFS: dir_truncate()\n");
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this