patch-2.3.2 linux/fs/hpfs/dir.c
Next file: linux/fs/hpfs/dnode.c
Previous file: linux/fs/hpfs/dentry.c
Back to the patch index
Back to the overall index
- Lines: 283
- Date:
Thu May 13 23:48:20 1999
- Orig file:
v2.3.1/linux/fs/hpfs/dir.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.3.1/linux/fs/hpfs/dir.c linux/fs/hpfs/dir.c
@@ -0,0 +1,282 @@
+/*
+ * linux/fs/hpfs/dir.c
+ *
+ * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
+ *
+ * directory VFS functions
+ */
+
+#include "hpfs_fn.h"
+
+int hpfs_dir_read(struct file *filp, char *name, size_t len, loff_t *loff)
+{
+ return -EISDIR;
+}
+
+int hpfs_dir_release(struct inode *inode, struct file *filp)
+{
+ hpfs_del_pos(inode, &filp->f_pos);
+ /*hpfs_write_if_changed(inode);*/
+ return 0;
+}
+
+int hpfs_readdir(struct file *filp, void * dirent, filldir_t filldir)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct quad_buffer_head qbh;
+ struct hpfs_dirent *de;
+ int lc;
+ long old_pos;
+ char *tempname;
+ int c1, c2 = 0;
+
+ if (!inode) return -EBADF;
+ if (!S_ISDIR(inode->i_mode)) return -EBADF;
+ if (inode->i_sb->s_hpfs_chk) {
+ if (hpfs_chk_sectors(inode->i_sb, inode->i_ino, 1, "dir_fnode"))
+ return -EFSERROR;
+ if (hpfs_chk_sectors(inode->i_sb, inode->i_hpfs_dno, 4, "dir_dnode"))
+ return -EFSERROR;
+ }
+ if (inode->i_sb->s_hpfs_chk >= 2) {
+ struct buffer_head *bh;
+ struct fnode *fno;
+ int e = 0;
+ if (!(fno = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh)))
+ return -EIOERROR;
+ if (!fno->dirflag) {
+ e = 1;
+ hpfs_error(inode->i_sb, "not a directory, fnode %08x",inode->i_ino);
+ }
+ if (inode->i_hpfs_dno != fno->u.external[0].disk_secno) {
+ e = 1;
+ hpfs_error(inode->i_sb, "corrupted inode: i_hpfs_dno == %08x, fnode -> dnode == %08x", inode->i_hpfs_dno, fno->u.external[0].disk_secno);
+ }
+ brelse(bh);
+ if (e) return -EFSERROR;
+ }
+ lc = inode->i_sb->s_hpfs_lowercase;
+ if (filp->f_pos == -2) { /* diff -r requires this (note, that diff -r */
+ filp->f_pos = -3; /* also fails on msdos filesystem in 2.0) */
+ return 0;
+ }
+ if (filp->f_pos == -3) return -ENOENT;
+
+ hpfs_lock_inode(inode);
+
+ while (1) {
+ again:
+ /* This won't work when cycle is longer than number of dirents
+ accepted by filldir, but what can I do?
+ maybe killall -9 ls helps */
+ if (inode->i_sb->s_hpfs_chk)
+ if (hpfs_stop_cycles(inode->i_sb, filp->f_pos, &c1, &c2, "hpfs_readdir")) {
+ hpfs_unlock_inode(inode);
+ return -EFSERROR;
+ }
+ if (filp->f_pos == -2) {
+ hpfs_unlock_inode(inode);
+ return 0;
+ }
+ if (filp->f_pos == 3 || filp->f_pos == 4 || filp->f_pos == 5) {
+ printk("HPFS: warning: pos==%d\n",(int)filp->f_pos);
+ hpfs_unlock_inode(inode);
+ return 0;
+ }
+ if (filp->f_pos == 0) {
+ if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0) {
+ hpfs_unlock_inode(inode);
+ return 0;
+ }
+ filp->f_pos = -1;
+ }
+ if (filp->f_pos == -1) {
+ if (filldir(dirent, "..", 2, filp->f_pos, inode->i_hpfs_parent_dir) < 0) {
+ hpfs_unlock_inode(inode);
+ return 0;
+ }
+ filp->f_pos = 1;
+ }
+ if (filp->f_pos == 1) {
+ filp->f_pos = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, inode->i_hpfs_dno) << 4) + 1;
+ hpfs_add_pos(inode, &filp->f_pos);
+ filp->f_version = inode->i_version;
+ }
+ /*if (filp->f_version != inode->i_version) {
+ hpfs_unlock_inode(inode);
+ return -ENOENT;
+ }*/
+ old_pos = filp->f_pos;
+ if (!(de = map_pos_dirent(inode, &filp->f_pos, &qbh))) {
+ hpfs_unlock_inode(inode);
+ return -EIOERROR;
+ }
+ if (de->first || de->last) {
+ if (inode->i_sb->s_hpfs_chk) {
+ if (de->first && !de->last && (de->namelen != 2 || de ->name[0] != 1 || de->name[1] != 1)) hpfs_error(inode->i_sb, "hpfs_readdir: bad ^A^A entry; pos = %08x", old_pos);
+ if (de->last && (de->namelen != 1 || de ->name[0] != 255)) hpfs_error(inode->i_sb, "hpfs_readdir: bad \\377 entry; pos = %08x", old_pos);
+ }
+ hpfs_brelse4(&qbh);
+ goto again;
+ }
+ tempname = hpfs_translate_name(inode->i_sb, de->name, de->namelen, lc, de->not_8x3);
+ if (filldir(dirent, tempname, de->namelen, old_pos, de->fnode) < 0) {
+ filp->f_pos = old_pos;
+ if (tempname != (char *)de->name) kfree(tempname);
+ hpfs_brelse4(&qbh);
+ hpfs_unlock_inode(inode);
+ return 0;
+ }
+ if (tempname != (char *)de->name) kfree(tempname);
+ hpfs_brelse4(&qbh);
+ }
+}
+
+/*
+ * lookup. Search the specified directory for the specified name, set
+ * *result to the corresponding inode.
+ *
+ * lookup uses the inode number to tell read_inode whether it is reading
+ * the inode of a directory or a file -- file ino's are odd, directory
+ * ino's are even. read_inode avoids i/o for file inodes; everything
+ * needed is up here in the directory. (And file fnodes are out in
+ * the boondocks.)
+ *
+ * - M.P.: this is over, sometimes we've got to read file's fnode for eas
+ * inode numbers are just fnode sector numbers; iget lock is used
+ * to tell read_inode to read fnode or not.
+ */
+
+struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry)
+{
+ const char *name = dentry->d_name.name;
+ int len = dentry->d_name.len;
+ struct quad_buffer_head qbh;
+ struct hpfs_dirent *de;
+ struct inode *inode;
+ ino_t ino;
+
+ struct inode *result = NULL;
+ if (dir == 0) return -ENOENT;
+ hpfs_adjust_length((char *)name, &len);
+ hpfs_lock_inode(dir);
+ if (!S_ISDIR(dir->i_mode)) goto bail;
+ /*
+ * Read in the directory entry. "." is there under the name ^A^A .
+ * Always read the dir even for . and .. in case we need the dates.
+ *
+ * M.P.: No - we can't read '^A^A' for current directory. In some cases
+ * the information under '^A^A' is incomplete (missing ea_size, bad
+ * fnode number) - chkdsk ignores such errors and it doesn't seem to
+ * matter under OS/2.
+ */
+ if (name[0] == '.' && len == 1) {
+ result = dir;
+ dir->i_count++;
+ goto end;
+ } else if (name[0] == '.' && name[1] == '.' && len == 2) {
+ struct buffer_head *bh;
+ struct fnode *fnode;
+ if (dir->i_ino == dir->i_sb->s_hpfs_root) {
+ result = dir;
+ dir->i_count++;
+ goto end;
+ }
+ if (dir->i_hpfs_parent_dir == dir->i_sb->s_hpfs_root) {
+ result = dir->i_sb->s_root->d_inode;
+ result->i_count++;
+ goto end;
+ }
+ if (!(fnode = hpfs_map_fnode(dir->i_sb, dir->i_hpfs_parent_dir, &bh))) goto bail;
+ de = map_fnode_dirent(dir->i_sb, dir->i_hpfs_parent_dir, fnode, &qbh);
+ brelse(bh);
+ } else
+ de = map_dirent(dir, dir->i_hpfs_dno, (char *) name, len, NULL, &qbh, NULL);
+
+ /*
+ * This is not really a bailout, just means file not found.
+ */
+
+ if (!de) {
+ result = NULL;
+ goto end;
+ }
+
+ /*
+ * Get inode number, what we're after.
+ */
+
+ ino = de->fnode;
+
+ /*
+ * Go find or make an inode.
+ */
+
+ hpfs_lock_iget(dir->i_sb, de->directory || (de->ea_size && dir->i_sb->s_hpfs_eas) ? 1 : 2);
+ if (!(inode = iget(dir->i_sb, ino))) {
+ hpfs_unlock_iget(dir->i_sb);
+ hpfs_error(inode->i_sb, "hpfs_lookup: can't get inode");
+ goto bail1;
+ }
+ if (!de->directory) inode->i_hpfs_parent_dir = dir->i_ino;
+ hpfs_unlock_iget(dir->i_sb);
+
+ hpfs_decide_conv(inode, (char *)name, len);
+
+ if (de->has_acl || de->has_xtd_perm) if (!(dir->i_sb->s_flags & MS_RDONLY)) {
+ hpfs_error(inode->i_sb, "ACLs or XPERM found. This is probably HPFS386. This driver doesn't support it now. Send me some info on these structures");
+ goto bail1;
+ }
+
+ /*
+ * Fill in the info from the directory if this is a newly created
+ * inode.
+ */
+
+ if (!inode->i_ctime) {
+ if (!(inode->i_ctime = local_to_gmt(dir->i_sb, de->creation_date)))
+ inode->i_ctime = 1;
+ inode->i_mtime = local_to_gmt(dir->i_sb, de->write_date);
+ inode->i_atime = local_to_gmt(dir->i_sb, de->read_date);
+ inode->i_hpfs_ea_size = de->ea_size;
+ if (!inode->i_hpfs_ea_mode && de->read_only)
+ inode->i_mode &= ~0222;
+ if (!de->directory) {
+ if (inode->i_size == -1) {
+ inode->i_size = de->file_size;
+ /*
+ * i_blocks should count the fnode and any anodes.
+ * We count 1 for the fnode and don't bother about
+ * anodes -- the disk heads are on the directory band
+ * and we want them to stay there.
+ */
+ inode->i_blocks = 1 + ((inode->i_size + 511) >> 9);
+ }
+ }
+ }
+
+ hpfs_brelse4(&qbh);
+
+ /*
+ * Made it.
+ */
+
+ result = inode;
+ end:
+ hpfs_unlock_inode(dir);
+ hpfs_set_dentry_operations(dentry);
+ d_add(dentry, result);
+ return NULL;
+
+ /*
+ * Didn't.
+ */
+ bail1:
+
+ hpfs_brelse4(&qbh);
+
+ bail:
+
+ hpfs_unlock_inode(dir);
+ return ERR_PTR(-ENOENT);
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)