summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-06-21 22:16:05 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-06-21 22:16:05 +0000
commit73ed328f3a698087551b4d6a36196b0819bc38af (patch)
treed0907f2e7e5f36ea0808ed6b1f10c5caf51478a5 /fs
parent89a61cd744a621efff2a4d7f0d99258f850338f2 (diff)
Cleanup, sync with others sources.
Diffstat (limited to 'fs')
-rw-r--r--fs/Config.in1
-rw-r--r--fs/hpfs/hpfs_caps.c171
-rw-r--r--fs/hpfs/hpfs_caps.h4
-rw-r--r--fs/hpfs/hpfs_fs.c1759
4 files changed, 1 insertions, 1934 deletions
diff --git a/fs/Config.in b/fs/Config.in
index 515a6ae9a..830e18ffe 100644
--- a/fs/Config.in
+++ b/fs/Config.in
@@ -59,6 +59,7 @@ if [ "$CONFIG_UFS_FS" != "n" ]; then
bool ' UFS filesystem write support (experimental)' CONFIG_UFS_FS_WRITE
fi
+
if [ "$CONFIG_NET" = "y" ]; then
mainmenu_option next_comment
diff --git a/fs/hpfs/hpfs_caps.c b/fs/hpfs/hpfs_caps.c
deleted file mode 100644
index 1a1b22320..000000000
--- a/fs/hpfs/hpfs_caps.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/* Capitalization rules for HPFS */
-
-/* In OS/2, HPFS filenames preserve upper and lower case letter distinctions
- but filename matching ignores case. That is, creating a file "Foo"
- actually creates a file named "Foo" which can be looked up as "Foo",
- "foo", or "FOO", among other possibilities.
-
- Also, HPFS is internationalized -- a table giving the uppercase
- equivalent of every character is stored in the filesystem, so that
- any national character set may be used. If several different
- national character sets are in use, several tables are stored
- in the filesystem.
-
- It would be perfectly reasonable for Linux HPFS to act as a Unix
- filesystem and match "Foo" only if asked for "Foo" exactly. But
- the sort order of HPFS directories is case-insensitive, so Linux
- still has to know the capitalization rules used by OS/2. Because
- of this, it turns out to be more natural for us to be case-insensitive
- than not.
-
- Currently the standard character set used by Linux is Latin-1.
- Work is underway to permit people to use UTF-8 instead, therefore
- all code that depends on the character set is segregated here.
-
- (It would be wonderful if Linux HPFS could be independent of what
- character set is in use on the Linux side, but because of the
- necessary case folding this is impossible.)
-
- There is a map from Latin-1 into code page 850 for every printing
- character in Latin-1. The NLS documentation of OS/2 shows that
- everybody has 850 available unless they don't have Western latin
- chars available at all (so fitting them to Linux without Unicode
- is a doomed exercise).
-
- It is not clear exactly how HPFS.IFS handles the situation when
- multiple code pages are in use. Experiments show that
-
- - tables on the disk give uppercasing rules for the installed code pages
-
- - each directory entry is tagged with what code page was current
- when that name was created
-
- - doing just CHCP, without changing what's on the disk in any way,
- can change what DIR reports, and what name a case-folded match
- will match.
-
- This means, I think, that HPFS.IFS operates in the current code
- page, without regard to the uppercasing information recorded in
- the tables on the disk. It does record the uppercasing rules
- it used, perhaps for CHKDSK, but it does not appear to use them
- itself.
-
- So: Linux, a Latin-1 system, will operate in code page 850. We
- recode between 850 and Latin-1 when dealing with the names actually
- on the disk. We don't use the uppercasing tables either.
-
- In a hypothetical UTF-8 implementation, one reasonable way to
- proceed that matches OS/2 (for least surprise) is: do case
- translation in UTF-8, and recode to/from one of the code pages
- available on the mounted filesystem. Reject as invalid any name
- containing chars that can't be represented on disk by one of the
- code pages OS/2 is using. Recoding from on-disk names to UTF-8
- could use the code page tags, though this is not what OS/2 does. */
-
-
-static const unsigned char tb_cp850_to_latin1[128] =
-{
- 199, 252, 233, 226, 228, 224, 229, 231,
- 234, 235, 232, 239, 238, 236, 196, 197,
- 201, 230, 198, 244, 246, 242, 251, 249,
- 255, 214, 220, 248, 163, 216, 215, 159,
- 225, 237, 243, 250, 241, 209, 170, 186,
- 191, 174, 172, 189, 188, 161, 171, 187,
- 155, 156, 157, 144, 151, 193, 194, 192,
- 169, 135, 128, 131, 133, 162, 165, 147,
- 148, 153, 152, 150, 145, 154, 227, 195,
- 132, 130, 137, 136, 134, 129, 138, 164,
- 240, 208, 202, 203, 200, 158, 205, 206,
- 207, 149, 146, 141, 140, 166, 204, 139,
- 211, 223, 212, 210, 245, 213, 181, 254,
- 222, 218, 219, 217, 253, 221, 175, 180,
- 173, 177, 143, 190, 182, 167, 247, 184,
- 176, 168, 183, 185, 179, 178, 142, 160,
-};
-
-#if 0
-static const unsigned char tb_latin1_to_cp850[128] =
-{
- 186, 205, 201, 187, 200, 188, 204, 185,
- 203, 202, 206, 223, 220, 219, 254, 242,
- 179, 196, 218, 191, 192, 217, 195, 180,
- 194, 193, 197, 176, 177, 178, 213, 159,
- 255, 173, 189, 156, 207, 190, 221, 245,
- 249, 184, 166, 174, 170, 240, 169, 238,
- 248, 241, 253, 252, 239, 230, 244, 250,
- 247, 251, 167, 175, 172, 171, 243, 168,
- 183, 181, 182, 199, 142, 143, 146, 128,
- 212, 144, 210, 211, 222, 214, 215, 216,
- 209, 165, 227, 224, 226, 229, 153, 158,
- 157, 235, 233, 234, 154, 237, 232, 225,
- 133, 160, 131, 198, 132, 134, 145, 135,
- 138, 130, 136, 137, 141, 161, 140, 139,
- 208, 164, 149, 162, 147, 228, 148, 246,
- 155, 151, 163, 150, 129, 236, 231, 152,
-};
-#endif
-
-#define A_GRAVE 0300
-#define THORN 0336
-#define MULTIPLY 0327
-#define a_grave 0340
-#define thorn 0376
-#define divide 0367
-
-static inline unsigned latin1_upcase (unsigned c)
-{
- if (c - 'a' <= 'z' - 'a'
- || (c - a_grave <= thorn - a_grave
- && c != divide))
- return c - 'a' + 'A';
- else
- return c;
-}
-
-static inline unsigned latin1_downcase (unsigned c)
-{
- if (c - 'A' <= 'Z' - 'A'
- || (c - A_GRAVE <= THORN - A_GRAVE
- && c != MULTIPLY))
- return c + 'a' - 'A';
- else
- return c;
-}
-
-#if 0
-static inline unsigned latin1_to_cp850 (unsigned c)
-{
- if ((signed) c - 128 >= 0)
- return tb_latin1_to_cp850[c - 128];
- else
- return c;
-}
-#endif
-
-static inline unsigned cp850_to_latin1 (unsigned c)
-{
- if ((signed) c - 128 >= 0)
- return tb_cp850_to_latin1[c - 128];
- else
- return c;
-}
-
-unsigned hpfs_char_to_upper_linux (unsigned c)
-{
- return latin1_upcase (cp850_to_latin1 (c));
-}
-
-unsigned linux_char_to_upper_linux (unsigned c)
-{
- return latin1_upcase (c);
-}
-
-unsigned hpfs_char_to_lower_linux (unsigned c)
-{
- return latin1_downcase (cp850_to_latin1 (c));
-}
-
-unsigned hpfs_char_to_linux (unsigned c)
-{
- return cp850_to_latin1 (c);
-}
diff --git a/fs/hpfs/hpfs_caps.h b/fs/hpfs/hpfs_caps.h
deleted file mode 100644
index c4e49e97d..000000000
--- a/fs/hpfs/hpfs_caps.h
+++ /dev/null
@@ -1,4 +0,0 @@
-unsigned hpfs_char_to_linux (unsigned c);
-unsigned hpfs_char_to_lower_linux (unsigned c);
-unsigned hpfs_char_to_upper_linux (unsigned c);
-unsigned linux_char_to_upper_linux (unsigned c);
diff --git a/fs/hpfs/hpfs_fs.c b/fs/hpfs/hpfs_fs.c
deleted file mode 100644
index cb1d0215b..000000000
--- a/fs/hpfs/hpfs_fs.c
+++ /dev/null
@@ -1,1759 +0,0 @@
-/*
- * linux/fs/hpfs/hpfs_fs.c
- * read-only HPFS
- * version 1.0
- *
- * Chris Smith 1993
- *
- * Sources & references:
- * Duncan, _Design ... of HPFS_, MSJ 4(5) (C) 1989 Microsoft Corp
- * linux/fs/minix Copyright (C) 1991, 1992, 1993 Linus Torvalds
- * linux/fs/msdos Written 1992, 1993 by Werner Almesberger
- * linux/fs/isofs Copyright (C) 1991 Eric Youngdale
- */
-
-#include <linux/module.h>
-
-#include <linux/fs.h>
-#include <linux/hpfs_fs.h>
-#include <linux/errno.h>
-#include <linux/malloc.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/locks.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <asm/bitops.h>
-#include <asm/uaccess.h>
-
-#include "hpfs.h"
-#include "hpfs_caps.h"
-
-/*
- * HPFS is a mixture of 512-byte blocks and 2048-byte blocks. The 2k blocks
- * are used for directories and bitmaps. For bmap to work, we must run the
- * file system with 512-byte blocks. The 2k blocks are assembled in buffers
- * obtained from kmalloc.
- *
- * For a file's i-number we use the sector number of its fnode, coded.
- * (Directory ino's are even, file ino's are odd, and ino >> 1 is the
- * sector address of the fnode. This is a hack to allow lookup() to
- * tell read_inode() whether it is necessary to read the fnode.)
- *
- * The map_xxx routines all read something into a buffer and return a
- * pointer somewhere in the buffer. The caller must do the brelse.
- * The other routines are balanced.
- *
- * For details on the data structures see hpfs.h and the Duncan paper.
- *
- * Overview
- *
- * [ The names of these data structures, except fnode, are not Microsoft's
- * or IBM's. I don't know what names they use. The semantics described
- * here are those of this implementation, and any coincidence between it
- * and real HPFS is to be hoped for but not guaranteed by me, and
- * certainly not guaranteed by MS or IBM. Who know nothing about this. ]
- *
- * [ Also, the following will make little sense if you haven't read the
- * Duncan paper, which is excellent. ]
- *
- * HPFS is a tree. There are 3 kinds of nodes. A directory is a tree
- * of dnodes, and a file's allocation info is a tree of sector runs
- * stored in fnodes and anodes.
- *
- * The top pointer is in the super block, it points to the fnode of the
- * root directory.
- *
- * The root directory -- all directories -- gives file names, dates &c,
- * and fnode addresses. If the directory fits in one dnode, that's it,
- * otherwise the top dnode points to other dnodes, forming a tree. A
- * dnode tree (one directory) might look like
- *
- * ((a b c) d (e f g) h (i j) k l (m n o p))
- *
- * The subtrees appear between the files. Each dir entry contains, along
- * with the name and fnode, a dnode pointer to the subtree that precedes it
- * (if there is one; a flag tells that). The first entry in every directory
- * is ^A^A, the "." entry for the directory itself. The last entry in every
- * dnode is \377, a fake entry whose only valid fields are the bit marking
- * it last and the down pointer to the subtree preceding it, if any.
- *
- * The "value" field of directory entries is an fnode address. The fnode
- * tells where the sectors of the file are. The fnode for a subdirectory
- * contains one pointer, to the root dnode of the subdirectory. The fnode
- * for a data file contains, in effect, a tiny anode. (Most of the space
- * in fnodes is for extended attributes.)
- *
- * anodes and the anode part of fnodes are trees of extents. An extent
- * is a (length, disk address) pair, labeled with the file address being
- * mapped. E.g.,
- *
- * (0: 3@1000 3: 1@2000 4: 2@10)
- *
- * means the file:disk sector map (0:1000 1:1001 2:1002 3:2000 4:10 5:11).
- *
- * There is space for 8 file:len@disk triples in an fnode, or for 40 in an
- * anode. If this is insufficient, subtrees are used, as in
- *
- * (6: (0: 3@1000 3: 1@2000 4: 2@10) 12: (6: 3@8000 9: 1@9000 10: 2@20))
- *
- * The label on a subtree is the first address *after* that tree. The
- * subtrees are always anodes. The label:subtree pairs require only
- * two words each, so non-leaf subtrees have a different format; there
- * is room for 12 label:subtree pairs in an fnode, or 60 in an anode.
- *
- * Within a directory, each dnode contains a pointer up to its parent
- * dnode. The root dnode points up to the directory's fnode.
- *
- * Each fnode contains a pointer to the directory that contains it
- * (to the fnode of the directory). So this pointer in a directory
- * fnode is "..".
- *
- * On the disk, dnodes are all together in the center of the partition,
- * and HPFS even manages to put all the dnodes for a single directory
- * together, generally. fnodes are out with the data. anodes are seldom
- * seen -- in fact noncontiguous files are seldom seen. I think this is
- * partly the open() call that lets programs specify the length of an
- * output file when they know it, and partly because HPFS.IFS really is
- * very good at resisting fragmentation.
- */
-
-/* notation */
-
-#define little_ushort(x) (*(unsigned short *) &(x))
-typedef void nonconst;
-
-/* super block ops */
-
-static void hpfs_read_inode(struct inode *);
-static void hpfs_put_super(struct super_block *);
-static int hpfs_statfs(struct super_block *, struct statfs *, int);
-static int hpfs_remount_fs(struct super_block *, int *, char *);
-
-static const struct super_operations hpfs_sops =
-{
- hpfs_read_inode, /* read_inode */
- NULL, /* write_inode */
- NULL, /* put_inode */
- NULL, /* delete_inode */
- NULL, /* notify_change */
- hpfs_put_super, /* put_super */
- NULL, /* write_super */
- hpfs_statfs, /* statfs */
- hpfs_remount_fs, /* remount_fs */
-};
-
-/* file ops */
-
-static ssize_t hpfs_file_read(struct file *, char *, size_t, loff_t *);
-static secno hpfs_bmap(struct inode *, unsigned);
-
-static const struct file_operations hpfs_file_ops =
-{
- NULL, /* lseek - default */
- hpfs_file_read, /* read */
- NULL, /* write */
- NULL, /* readdir - bad */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- generic_file_mmap, /* mmap */
- NULL, /* no special open is needed */
- NULL, /* flush */
- NULL, /* release */
- file_fsync, /* fsync */
-};
-
-static const struct inode_operations hpfs_file_iops =
-{
- (nonconst *) & hpfs_file_ops, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- generic_readpage, /* readpage */
- NULL, /* writepage */
- (int (*)(struct inode *, int))
- &hpfs_bmap, /* bmap */
- NULL, /* truncate */
- NULL, /* permission */
-};
-
-/* directory ops */
-
-static ssize_t hpfs_dir_read(struct file *filp, char *buf,
- size_t count, loff_t *ppos);
-static int hpfs_readdir(struct file *filp,
- void *dirent, filldir_t filldir);
-static struct dentry *hpfs_lookup(struct inode *, struct dentry *);
-
-static const struct file_operations hpfs_dir_ops =
-{
- NULL, /* lseek - default */
- hpfs_dir_read, /* read */
- NULL, /* write - bad */
- hpfs_readdir, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- file_fsync, /* fsync */
-};
-
-static const struct inode_operations hpfs_dir_iops =
-{
- (nonconst *) & hpfs_dir_ops, /* default directory file ops */
- NULL, /* create */
- hpfs_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* bmap */
- NULL, /* truncate */
- NULL, /* permission */
-};
-
-/* Four 512-byte buffers and the 2k block obtained by concatenating them */
-
-struct quad_buffer_head {
- struct buffer_head *bh[4];
- void *data;
-};
-
-/* forwards */
-
-static int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
- int *lowercase, int *conv, int *nocheck);
-static int check_warn(int not_ok,
- const char *p1, const char *p2, const char *p3);
-static int zerop(void *addr, unsigned len);
-static void count_dnodes(struct inode *inode, dnode_secno dno,
- unsigned *n_dnodes, unsigned *n_subdirs);
-static unsigned count_bitmap(struct super_block *s);
-static unsigned count_one_bitmap(kdev_t dev, secno secno);
-static secno bplus_lookup(struct inode *inode, struct bplus_header *b,
- secno file_secno, struct buffer_head **bhp);
-static struct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno,
- const unsigned char *name, unsigned len,
- struct quad_buffer_head *qbh);
-static struct hpfs_dirent *map_pos_dirent(struct inode *inode, loff_t *posp,
- struct quad_buffer_head *qbh);
-static dnode_secno dir_subdno(struct inode *inode, unsigned pos);
-static struct hpfs_dirent *map_nth_dirent(kdev_t dev, dnode_secno dno,
- int n,
- struct quad_buffer_head *qbh);
-static unsigned choose_conv(unsigned char *p, unsigned len);
-static unsigned convcpy_tofs(unsigned char *out, unsigned char *in,
- unsigned len);
-static dnode_secno fnode_dno(kdev_t dev, ino_t ino);
-static struct fnode *map_fnode(kdev_t dev, ino_t ino,
- struct buffer_head **bhp);
-static struct anode *map_anode(kdev_t dev, unsigned secno,
- struct buffer_head **bhp);
-static struct dnode *map_dnode(kdev_t dev, unsigned secno,
- struct quad_buffer_head *qbh);
-static void *map_sector(kdev_t dev, unsigned secno, struct buffer_head **bhp);
-static void *map_4sectors(kdev_t dev, unsigned secno,
- struct quad_buffer_head *qbh);
-static void brelse4(struct quad_buffer_head *qbh);
-
-/*
- * make inode number for a file
- */
-
-static inline ino_t file_ino(fnode_secno secno)
-{
- return secno << 1 | 1;
-}
-
-/*
- * make inode number for a directory
- */
-
-static inline ino_t dir_ino(fnode_secno secno)
-{
- return secno << 1;
-}
-
-/*
- * get fnode address from an inode number
- */
-
-static inline fnode_secno ino_secno(ino_t ino)
-{
- return ino >> 1;
-}
-
-/*
- * test for directory's inode number
- */
-
-static inline int ino_is_dir(ino_t ino)
-{
- return (ino & 1) == 0;
-}
-
-/*
- * conv= options
- */
-
-#define CONV_BINARY 0 /* no conversion */
-#define CONV_TEXT 1 /* crlf->newline */
-#define CONV_AUTO 2 /* decide based on file contents */
-
-/*
- * local time (HPFS) to GMT (Unix)
- */
-
-static inline time_t local_to_gmt(time_t t)
-{
- extern struct timezone sys_tz;
- return t + sys_tz.tz_minuteswest * 60 - (sys_tz.tz_dsttime ? 3600 : 0);
-}
-
-/* super block ops */
-
-/*
- * mount. This gets one thing, the root directory inode. It does a
- * bunch of guessed-at consistency checks.
- */
-
-struct super_block *hpfs_read_super(struct super_block *s,
- void *options, int silent)
-{
- struct hpfs_boot_block *bootblock;
- struct hpfs_super_block *superblock;
- struct hpfs_spare_block *spareblock;
- struct hpfs_dirent *de = NULL;
- struct buffer_head *bh0, *bh1, *bh2;
- struct quad_buffer_head qbh;
- dnode_secno root_dno;
- kdev_t dev;
- uid_t uid;
- gid_t gid;
- umode_t umask;
- int lowercase;
- int conv;
- int dubious;
- int nocheck;
-
- MOD_INC_USE_COUNT;
-
- /*
- * Get the mount options
- */
-
- if (!parse_opts(options, &uid, &gid, &umask, &lowercase, &conv,
- &nocheck)) {
- printk("HPFS: syntax error in mount options. Not mounted.\n");
- s->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return 0;
- }
-
- /*
- * Fill in the super block struct
- */
-
- lock_super(s);
- dev = s->s_dev;
- set_blocksize(dev, 512);
-
- /*
- * fetch sectors 0, 16, 17
- */
-
- bootblock = map_sector(dev, 0, &bh0);
- if (!bootblock)
- goto bail;
-
- superblock = map_sector(dev, 16, &bh1);
- if (!superblock)
- goto bail0;
-
- spareblock = map_sector(dev, 17, &bh2);
- if (!spareblock)
- goto bail1;
-
- /*
- * Check that this fs looks enough like a known one that we can find
- * and read the root directory.
- */
-
- if (bootblock->magic != 0xaa55
- || superblock->magic != SB_MAGIC
- || spareblock->magic != SP_MAGIC
- || bootblock->sig_28h != 0x28
- || memcmp(&bootblock->sig_hpfs, "HPFS ", 8)
- || little_ushort(bootblock->bytes_per_sector) != 512) {
- printk("HPFS: hpfs_read_super: Not HPFS\n");
- goto bail2;
- }
-
- /*
- * Check for inconsistencies -- possibly wrong guesses here, possibly
- * filesystem problems.
- */
-
- dubious = 0;
-
- dubious |= check_warn(spareblock->dirty != 0,
- "`Improperly stopped'", "flag is set", "run CHKDSK");
- dubious |= check_warn(spareblock->n_spares_used != 0,
- "Spare blocks", "may be in use", "run CHKDSK");
-
- /*
- * Above errors mean we could get wrong answers if we proceed,
- * so don't
- */
-
- if (dubious && !nocheck)
- goto bail2;
-
- dubious |= check_warn((spareblock->n_dnode_spares !=
- spareblock->n_dnode_spares_free),
- "Spare dnodes", "may be in use", "run CHKDSK");
- dubious |= check_warn(superblock->zero1 != 0,
- "#1", "unknown word nonzero", "investigate");
- dubious |= check_warn(superblock->zero3 != 0,
- "#3", "unknown word nonzero", "investigate");
- dubious |= check_warn(superblock->zero4 != 0,
- "#4", "unknown word nonzero", "investigate");
- dubious |= check_warn(!zerop(superblock->zero5,
- sizeof superblock->zero5),
- "#5", "unknown word nonzero", "investigate");
- dubious |= check_warn(!zerop(superblock->zero6,
- sizeof superblock->zero6),
- "#6", "unknown word nonzero", "investigate");
-
- if (dubious)
- printk("HPFS: Proceeding, but operation may be unreliable\n");
-
- /*
- * set fs read only
- */
-
- s->s_flags |= MS_RDONLY;
-
- /*
- * fill in standard stuff
- */
-
- s->s_magic = HPFS_SUPER_MAGIC;
- s->s_blocksize = 512;
- s->s_blocksize_bits = 9;
- s->s_op = (struct super_operations *) &hpfs_sops;
-
- /*
- * fill in hpfs stuff
- */
-
- s->s_hpfs_root = dir_ino(superblock->root);
- s->s_hpfs_fs_size = superblock->n_sectors;
- s->s_hpfs_dirband_size = superblock->n_dir_band / 4;
- s->s_hpfs_dmap = superblock->dir_band_bitmap;
- s->s_hpfs_bitmaps = superblock->bitmaps;
- s->s_hpfs_uid = uid;
- s->s_hpfs_gid = gid;
- s->s_hpfs_mode = 0777 & ~umask;
- s->s_hpfs_n_free = -1;
- s->s_hpfs_n_free_dnodes = -1;
- s->s_hpfs_lowercase = lowercase;
- s->s_hpfs_conv = conv;
-
- /*
- * done with the low blocks
- */
-
- brelse(bh2);
- brelse(bh1);
- brelse(bh0);
-
- /*
- * all set. try it out.
- */
-
- s->s_root = d_alloc_root(iget(s, s->s_hpfs_root), NULL);
- unlock_super(s);
-
- if (!s->s_root) {
- printk("HPFS: hpfs_read_super: inode get failed\n");
- s->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return 0;
- }
-
- /*
- * find the root directory's . pointer & finish filling in the inode
- */
-
- root_dno = fnode_dno(dev, s->s_hpfs_root);
- if (root_dno)
- de = map_dirent(s->s_root->d_inode, root_dno,
- "\001\001", 2, &qbh);
- if (!root_dno || !de) {
- printk("HPFS: "
- "hpfs_read_super: root dir isn't in the root dir\n");
- s->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return 0;
- }
-
- s->s_root->d_inode->i_atime = local_to_gmt(de->read_date);
- s->s_root->d_inode->i_mtime = local_to_gmt(de->write_date);
- s->s_root->d_inode->i_ctime = local_to_gmt(de->creation_date);
-
- brelse4(&qbh);
- return s;
-
- bail2:
- brelse(bh2);
- bail1:
- brelse(bh1);
- bail0:
- brelse(bh0);
- bail:
- s->s_dev = 0;
- unlock_super(s);
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-static int check_warn(int not_ok,
- const char *p1, const char *p2, const char *p3)
-{
- if (not_ok)
- printk("HPFS: %s %s. Please %s\n", p1, p2, p3);
- return not_ok;
-}
-
-static int zerop(void *addr, unsigned len)
-{
- unsigned char *p = addr;
- return p[0] == 0 && memcmp(p, p + 1, len - 1) == 0;
-}
-
-/*
- * A tiny parser for option strings, stolen from dosfs.
- */
-
-static int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
- int *lowercase, int *conv, int *nocheck)
-{
- char *p, *rhs;
-
- *uid = current->uid;
- *gid = current->gid;
- *umask = current->fs->umask;
- *lowercase = 1;
- *conv = CONV_BINARY;
- *nocheck = 0;
-
- if (!opts)
- return 1;
-
- for (p = strtok(opts, ","); p != 0; p = strtok(0, ",")) {
- if ((rhs = strchr(p, '=')) != 0)
- *rhs++ = '\0';
- if (!strcmp(p, "uid")) {
- if (!rhs || !*rhs)
- return 0;
- *uid = simple_strtoul(rhs, &rhs, 0);
- if (*rhs)
- return 0;
- }
- else if (!strcmp(p, "gid")) {
- if (!rhs || !*rhs)
- return 0;
- *gid = simple_strtoul(rhs, &rhs, 0);
- if (*rhs)
- return 0;
- }
- else if (!strcmp(p, "umask")) {
- if (!rhs || !*rhs)
- return 0;
- *umask = simple_strtoul(rhs, &rhs, 8);
- if (*rhs)
- return 0;
- }
- else if (!strcmp(p, "case")) {
- if (!strcmp(rhs, "lower"))
- *lowercase = 1;
- else if (!strcmp(rhs, "asis"))
- *lowercase = 0;
- else
- return 0;
- }
- else if (!strcmp(p, "conv")) {
- if (!strcmp(rhs, "binary"))
- *conv = CONV_BINARY;
- else if (!strcmp(rhs, "text"))
- *conv = CONV_TEXT;
- else if (!strcmp(rhs, "auto"))
- *conv = CONV_AUTO;
- else
- return 0;
- }
- else if (!strcmp(p,"nocheck"))
- *nocheck=1;
- else
- return 1;
- }
-
- return 1;
-}
-
-/*
- * read_inode. This is called with exclusive access to a new inode that
- * has only (i_dev,i_ino) set. It is responsible for filling in the rest.
- * We leave the dates blank, to be filled in from the dir entry.
- *
- * NOTE that there must be no sleeping from the return in this routine
- * until lookup() finishes filling in the inode, otherwise the partly
- * completed inode would be visible during the sleep.
- *
- * It is done in this strange and sinful way because the alternative
- * is to read the fnode, find the dir pointer in it, read that fnode
- * to get the dnode pointer, search through that whole directory for
- * the ino we're reading, and get the dates. It works that way, but
- * ls sounds like fsck.
- */
-
-static void hpfs_read_inode(struct inode *inode)
-{
- struct super_block *s = inode->i_sb;
-
- /* be ready to bail out */
-
- inode->i_op = 0;
- inode->i_mode = 0;
-
- if (inode->i_ino == 0
- || ino_secno(inode->i_ino) >= inode->i_sb->s_hpfs_fs_size) {
- printk("HPFS: read_inode: bad ino\n");
- return;
- }
-
- /*
- * canned stuff
- */
-
- inode->i_uid = s->s_hpfs_uid;
- inode->i_gid = s->s_hpfs_gid;
- inode->i_mode = s->s_hpfs_mode;
- inode->i_hpfs_conv = s->s_hpfs_conv;
-
- inode->i_hpfs_dno = 0;
- inode->i_hpfs_n_secs = 0;
- inode->i_hpfs_file_sec = 0;
- inode->i_hpfs_disk_sec = 0;
- inode->i_hpfs_dpos = 0;
- inode->i_hpfs_dsubdno = 0;
-
- /*
- * figure out whether we are looking at a directory or a file
- */
-
- if (ino_is_dir(inode->i_ino))
- inode->i_mode |= S_IFDIR;
- else {
- inode->i_mode |= S_IFREG;
- inode->i_mode &= ~0111;
- }
-
- /*
- * these fields must be filled in from the dir entry, which we don't
- * have but lookup does. It will fill them in before letting the
- * inode out of its grasp.
- */
-
- inode->i_atime = 0;
- inode->i_mtime = 0;
- inode->i_ctime = 0;
- inode->i_size = 0;
-
- /*
- * fill in the rest
- */
-
- if (S_ISREG(inode->i_mode)) {
-
- inode->i_op = (struct inode_operations *) &hpfs_file_iops;
- inode->i_nlink = 1;
- inode->i_blksize = 512;
-
- }
- else {
- unsigned n_dnodes, n_subdirs;
- struct buffer_head *bh0;
- struct fnode *fnode = map_fnode(inode->i_dev,
- inode->i_ino, &bh0);
-
- if (!fnode) {
- printk("HPFS: read_inode: no fnode\n");
- inode->i_mode = 0;
- return;
- }
-
- inode->i_hpfs_parent_dir = dir_ino(fnode->up);
- inode->i_hpfs_dno = fnode->u.external[0].disk_secno;
-
- brelse(bh0);
-
- n_dnodes = n_subdirs = 0;
- count_dnodes(inode, inode->i_hpfs_dno, &n_dnodes, &n_subdirs);
-
- inode->i_op = (struct inode_operations *) &hpfs_dir_iops;
- inode->i_blksize = 512; /* 2048 here confuses ls & du & ... */
- inode->i_blocks = 4 * n_dnodes;
- inode->i_size = 512 * inode->i_blocks;
- inode->i_nlink = 2 + n_subdirs;
- }
-}
-
-/*
- * unmount.
- */
-
-static void hpfs_put_super(struct super_block *s)
-{
- MOD_DEC_USE_COUNT;
-}
-
-/*
- * statfs. For free inode counts we report the count of dnodes in the
- * directory band -- not exactly right but pretty analogous.
- */
-
-static int hpfs_statfs(struct super_block *s, struct statfs *buf, int bufsiz)
-{
- struct statfs tmp;
-
- /*
- * count the bits in the bitmaps, unless we already have
- */
- if (s->s_hpfs_n_free == -1) {
- s->s_hpfs_n_free = count_bitmap(s);
- s->s_hpfs_n_free_dnodes =
- count_one_bitmap(s->s_dev, s->s_hpfs_dmap);
- }
-
- /*
- * fill in the user statfs struct
- */
- tmp.f_type = s->s_magic;
- tmp.f_bsize = 512;
- tmp.f_blocks = s->s_hpfs_fs_size;
- tmp.f_bfree = s->s_hpfs_n_free;
- tmp.f_bavail = s->s_hpfs_n_free;
- tmp.f_files = s->s_hpfs_dirband_size;
- tmp.f_ffree = s->s_hpfs_n_free_dnodes;
- tmp.f_namelen = 254;
-
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
-}
-
-/*
- * remount. Don't let read only be turned off.
- */
-
-static int hpfs_remount_fs(struct super_block *s, int *flags, char *data)
-{
- if (!(*flags & MS_RDONLY))
- return -EINVAL;
- return 0;
-}
-
-/*
- * count the dnodes in a directory, and the subdirs.
- */
-
-static void count_dnodes(struct inode *inode, dnode_secno dno,
- unsigned *n_dnodes, unsigned *n_subdirs)
-{
- struct quad_buffer_head qbh;
- struct dnode *dnode;
- struct hpfs_dirent *de;
- struct hpfs_dirent *de_end;
-
- dnode = map_dnode(inode->i_dev, dno, &qbh);
- if (!dnode)
- return;
- de = dnode_first_de(dnode);
- de_end = dnode_end_de(dnode);
-
- (*n_dnodes)++;
-
- for (; de < de_end; de = de_next_de(de)) {
- if (de->down)
- count_dnodes(inode, de_down_pointer(de),
- n_dnodes, n_subdirs);
- if (de->directory && !de->first)
- (*n_subdirs)++;
- if (de->last || de->length == 0)
- break;
- }
-
- brelse4(&qbh);
-}
-
-/*
- * count the bits in the free space bit maps
- */
-
-static unsigned count_bitmap(struct super_block *s)
-{
- unsigned n, count, n_bands;
- secno *bitmaps;
- struct quad_buffer_head qbh;
-
- /*
- * there is one bit map for each 16384 sectors
- */
- n_bands = (s->s_hpfs_fs_size + 0x3fff) >> 14;
-
- /*
- * their locations are given in an array pointed to by the super
- * block
- */
- bitmaps = map_4sectors(s->s_dev, s->s_hpfs_bitmaps, &qbh);
- if (!bitmaps)
- return 0;
-
- count = 0;
-
- /*
- * map each one and count the free sectors
- */
- for (n = 0; n < n_bands; n++)
- if (bitmaps[n] == 0)
- printk("HPFS: bit map pointer missing\n");
- else
- count += count_one_bitmap(s->s_dev, bitmaps[n]);
-
- brelse4(&qbh);
- return count;
-}
-
-/*
- * Read in one bit map, count the bits, return the count.
- */
-
-static unsigned count_one_bitmap(kdev_t dev, secno secno)
-{
- struct quad_buffer_head qbh;
- char *bits;
- unsigned i, count;
-
- bits = map_4sectors(dev, secno, &qbh);
- if (!bits)
- return 0;
-
- count = 0;
-
- for (i = 0; i < 8 * 2048; i++)
- count += (test_bit(i, bits) != 0);
- brelse4(&qbh);
-
- return count;
-}
-
-/* file ops */
-
-/*
- * read. Read the bytes, put them in buf, return the count.
- */
-
-static ssize_t hpfs_file_read(struct file *filp, char *buf,
- size_t count, loff_t *ppos)
-{
- struct inode *inode = filp->f_dentry->d_inode;
- size_t q, r, n, n0;
- struct buffer_head *bh;
- char *block;
- char *start;
-
- if (inode == 0 || !S_ISREG(inode->i_mode))
- return -EINVAL;
-
- /*
- * truncate count at EOF
- */
- if (count > inode->i_size - (off_t) *ppos)
- count = inode->i_size - *ppos;
-
- start = buf;
- while (count > 0) {
- /*
- * get file sector number, offset in sector, length to end of
- * sector
- */
- q = *ppos >> 9;
- r = *ppos & 511;
- n = 512 - r;
-
- /*
- * get length to copy to user buffer
- */
- if (n > count)
- n = count;
-
- /*
- * read the sector, copy to user
- */
- block = map_sector(inode->i_dev, hpfs_bmap(inode, q), &bh);
- if (!block)
- return -EIO;
-
- /*
- * but first decide if it has \r\n, if the mount option said
- * to do that
- */
- if (inode->i_hpfs_conv == CONV_AUTO)
- inode->i_hpfs_conv = choose_conv(block + r, n);
-
- if (inode->i_hpfs_conv == CONV_BINARY) {
- /*
- * regular copy, output length is same as input
- * length
- */
- copy_to_user(buf, block + r, n);
- n0 = n;
- }
- else {
- /*
- * squeeze out \r, output length varies
- */
- n0 = convcpy_tofs(buf, block + r, n);
- if (count > inode->i_size - (off_t) *ppos - n + n0)
- count = inode->i_size - *ppos - n + n0;
- }
-
- brelse(bh);
-
- /*
- * advance input n bytes, output n0 bytes
- */
- *ppos += n;
- buf += n0;
- count -= n0;
- }
-
- return buf - start;
-}
-
-/*
- * This routine implements conv=auto. Return CONV_BINARY or CONV_TEXT.
- */
-
-static unsigned choose_conv(unsigned char *p, unsigned len)
-{
- unsigned tvote, bvote;
- unsigned c;
-
- tvote = bvote = 0;
-
- while (len--) {
- c = *p++;
- if (c < ' ') {
- if (c == '\r' && len && *p == '\n')
- tvote += 10;
- else if (c == '\t' || c == '\n');
- else
- bvote += 5;
- } else if (c < '\177')
- tvote++;
- else
- bvote += 5;
- }
-
- if (tvote > bvote)
- return CONV_TEXT;
- else
- return CONV_BINARY;
-}
-
-/*
- * This routine implements conv=text. :s/crlf/nl/
- */
-
-static unsigned convcpy_tofs(unsigned char *out, unsigned char *in,
- unsigned len)
-{
- unsigned char *start = out;
-
- while (len--) {
- unsigned c = *in++;
- if (c == '\r' && (len == 0 || *in == '\n'));
- else
- put_user(c, out++);
- }
-
- return out - start;
-}
-
-/*
- * Return the disk sector number containing a file sector.
- */
-
-static secno hpfs_bmap(struct inode *inode, unsigned file_secno)
-{
- unsigned n, disk_secno;
- struct fnode *fnode;
- struct buffer_head *bh;
-
- /*
- * There is one sector run cached in the inode. See if the sector is
- * in it.
- */
-
- n = file_secno - inode->i_hpfs_file_sec;
- if (n < inode->i_hpfs_n_secs)
- return inode->i_hpfs_disk_sec + n;
-
- /*
- * No, read the fnode and go find the sector.
- */
-
- else {
- fnode = map_fnode(inode->i_dev, inode->i_ino, &bh);
- if (!fnode)
- return 0;
- disk_secno = bplus_lookup(inode, &fnode->btree,
- file_secno, &bh);
- brelse(bh);
- return disk_secno;
- }
-}
-
-/*
- * Search allocation tree *b for the given file sector number and return
- * the disk sector number. Buffer *bhp has the tree in it, and can be
- * reused for subtrees when access to *b is no longer needed.
- * *bhp is busy on entry and exit.
- */
-
-static secno bplus_lookup(struct inode *inode, struct bplus_header *b,
- secno file_secno, struct buffer_head **bhp)
-{
- int i;
-
- /*
- * A leaf-level tree gives a list of sector runs. Find the one
- * containing the file sector we want, cache the map info in the
- * inode for later, and return the corresponding disk sector.
- */
-
- if (!b->internal) {
- struct bplus_leaf_node *n = b->u.external;
- for (i = 0; i < b->n_used_nodes; i++) {
- unsigned t = file_secno - n[i].file_secno;
- if (t < n[i].length) {
- inode->i_hpfs_file_sec = n[i].file_secno;
- inode->i_hpfs_disk_sec = n[i].disk_secno;
- inode->i_hpfs_n_secs = n[i].length;
- return n[i].disk_secno + t;
- }
- }
- }
-
- /*
- * A non-leaf tree gives a list of subtrees. Find the one containing
- * the file sector we want, read it in, and recurse to search it.
- */
-
- else {
- struct bplus_internal_node *n = b->u.internal;
- for (i = 0; i < b->n_used_nodes; i++) {
- if (file_secno < n[i].file_secno) {
- struct anode *anode;
- anode_secno ano = n[i].down;
- brelse(*bhp);
- anode = map_anode(inode->i_dev, ano, bhp);
- if (!anode)
- break;
- return bplus_lookup(inode, &anode->btree,
- file_secno, bhp);
- }
- }
- }
-
- /*
- * If we get here there was a hole in the file. As far as I know we
- * never do get here, but falling off the end would be indelicate. So
- * return a pointer to a handy all-zero sector. This is not a
- * reasonable way to handle files with holes if they really do
- * happen.
- */
-
- printk("HPFS: bplus_lookup: sector not found\n");
- return 15;
-}
-
-/* directory ops */
-
-/*
- * 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.)
- */
-
-static struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry)
-{
- const char *name = dentry->d_name.name;
- int len = dentry->d_name.len;
- struct hpfs_dirent *de;
- struct inode *inode;
- ino_t ino;
- int retval;
- struct quad_buffer_head qbh;
-
- /*
- * 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.
- */
-
- if (name[0] == '.' && len == 1)
- de = map_dirent(dir, dir->i_hpfs_dno, "\001\001", 2, &qbh);
- else if (name[0] == '.' && name[1] == '.' && len == 2)
- de = map_dirent(dir,
- fnode_dno(dir->i_dev, dir->i_hpfs_parent_dir),
- "\001\001", 2, &qbh);
- else
- de = map_dirent(dir, dir->i_hpfs_dno, name, len, &qbh);
-
- /*
- * This is not really a bailout, just means file not found.
- */
-
- if (!de) {
- d_add(dentry, NULL);
- retval = 0;
- goto out;
- }
-
- /*
- * Get inode number, what we're after.
- */
-
- if (de->directory)
- ino = dir_ino(de->fnode);
- else
- ino = file_ino(de->fnode);
-
- /*
- * Go find or make an inode.
- */
-
- retval = -EACCES;
- if (!(inode = iget(dir->i_sb, ino)))
- goto free4;
-
- /*
- * Fill in the info from the directory if this is a newly created
- * inode.
- */
-
- if (!inode->i_atime) {
- inode->i_atime = local_to_gmt(de->read_date);
- inode->i_mtime = local_to_gmt(de->write_date);
- inode->i_ctime = local_to_gmt(de->creation_date);
- if (de->read_only)
- inode->i_mode &= ~0222;
- if (!de->directory) {
- 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);
- }
- }
-
- d_add(dentry, inode);
- retval = 0;
-
- free4:
- brelse4(&qbh);
-
- out:
- return ERR_PTR(retval);
-}
-
-/*
- * Compare two counted strings ignoring case.
- * HPFS directory order sorts letters as if they're upper case.
- */
-
-static inline int memcasecmp(const unsigned char *s1, const unsigned char *s2,
- unsigned n)
-{
- int t;
-
- if (n != 0)
- do {
- unsigned c1 = linux_char_to_upper_linux (*s1++);
- unsigned c2 = hpfs_char_to_upper_linux (*s2++);
- if ((t = c1 - c2) != 0)
- return t;
- } while (--n != 0);
-
- return 0;
-}
-
-/*
- * Search a directory for the given name, return a pointer to its dir entry
- * and a pointer to the buffer containing it.
- */
-
-static struct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno,
- const unsigned char *name, unsigned len,
- struct quad_buffer_head *qbh)
-{
- struct dnode *dnode;
- struct hpfs_dirent *de;
- struct hpfs_dirent *de_end;
- int t, l;
-
- /*
- * read the dnode at the root of our subtree
- */
- dnode = map_dnode(inode->i_dev, dno, qbh);
- if (!dnode)
- return 0;
-
- /*
- * get pointers to start and end+1 of dir entries
- */
- de = dnode_first_de(dnode);
- de_end = dnode_end_de(dnode);
-
- /*
- * look through the entries for the name we're after
- */
- for ( ; de < de_end; de = de_next_de(de)) {
-
- /*
- * compare names
- */
- l = len < de->namelen ? len : de->namelen;
- t = memcasecmp(name, de->name, l);
-
- /*
- * initial substring matches, compare lengths
- */
- if (t == 0) {
- t = len - de->namelen;
- /* bingo */
- if (t == 0)
- return de;
- }
-
- /*
- * wanted name .lt. dir name => not present.
- */
- if (t < 0) {
- /*
- * if there is a subtree, search it.
- */
- if (de->down) {
- dnode_secno sub_dno = de_down_pointer(de);
- brelse4(qbh);
- return map_dirent(inode, sub_dno,
- name, len, qbh);
- }
- else
- break;
- }
-
- /*
- * de->last is set on the last name in the dnode (it's always
- * a "\377" pseudo entry). de->length == 0 means we're about
- * to infinite loop. This test does nothing in a well-formed
- * dnode.
- */
- if (de->last || de->length == 0)
- break;
- }
-
- /*
- * name not found.
- */
- brelse4(qbh);
- return 0;
-}
-
-/*
- * readdir. Return exactly 1 dirent. (I tried and tried, but currently
- * the interface with libc just does not permit more than 1. If it gets
- * fixed, throw this out and just walk the tree and write records into
- * the user buffer.)
- *
- * [ we now can handle multiple dirents, although the current libc doesn't
- * use that. The way hpfs does this is pretty strange, as we need to do
- * the name translation etc before calling "filldir()". This is untested,
- * as I don't have any hpfs partitions to test against. Linus ]
- *
- * We keep track of our position in the dnode tree with a sort of
- * dewey-decimal record of subtree locations. Like so:
- *
- * (1 (1.1 1.2 1.3) 2 3 (3.1 (3.1.1 3.1.2) 3.2 3.3 (3.3.1)) 4)
- *
- * Subtrees appear after their file, out of lexical order,
- * which would be before their file. It's easier.
- *
- * A directory can't hold more than 56 files, so 6 bits are used for
- * position numbers. If the tree is so deep that the position encoding
- * doesn't fit, I'm sure something absolutely fascinating happens.
- *
- * The actual sequence of f_pos values is
- * 0 => . -1 => .. 1 1.1 ... 8.9 9 => files -2 => eof
- *
- * The directory inode caches one position-to-dnode correspondence so
- * we won't have to repeatedly scan the top levels of the tree.
- */
-
-/*
- * Translate the given name: Blam it to lowercase if the mount option said to.
- */
-
-static void translate_hpfs_name(const unsigned char * from, int len, char * to, int lowercase)
-{
- while (len > 0) {
- unsigned t = *from;
- len--;
- if (lowercase)
- t = hpfs_char_to_lower_linux (t);
- else
- t = hpfs_char_to_linux (t);
- *to = t;
- from++;
- to++;
- }
-}
-
-static int hpfs_readdir(struct file *filp, void * dirent,
- filldir_t filldir)
-{
- struct quad_buffer_head qbh;
- struct hpfs_dirent *de;
- int namelen, lc;
- ino_t ino;
- char * tempname;
- long old_pos;
- struct inode *inode = filp->f_dentry->d_inode;
-
- tempname = (char *) __get_free_page(GFP_KERNEL);
- if (!tempname)
- return -ENOMEM;
-
- lc = inode->i_sb->s_hpfs_lowercase;
- switch ((long) filp->f_pos) {
- case -2:
- break;
-
- case 0:
- if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0)
- break;
- filp->f_pos = -1;
- /* fall through */
-
- case -1:
- if (filldir(dirent, "..", 2, filp->f_pos, inode->i_hpfs_parent_dir) < 0)
- break;
- filp->f_pos = 1;
- /* fall through */
-
- default:
- for (;;) {
- old_pos = filp->f_pos;
- de = map_pos_dirent(inode, &filp->f_pos, &qbh);
- if (!de) {
- filp->f_pos = -2;
- break;
- }
- namelen = de->namelen;
- translate_hpfs_name(de->name, namelen, tempname, lc);
- if (de->directory)
- ino = dir_ino(de->fnode);
- else
- ino = file_ino(de->fnode);
- brelse4(&qbh);
- if (filldir(dirent, tempname, namelen, old_pos, ino) < 0) {
- filp->f_pos = old_pos;
- break;
- }
- }
- }
- free_page((unsigned long) tempname);
- return 0;
-}
-
-/*
- * Map the dir entry at subtree coordinates given by *posp, and
- * increment *posp to point to the following dir entry.
- */
-
-static struct hpfs_dirent *map_pos_dirent(struct inode *inode, loff_t *posp,
- struct quad_buffer_head *qbh)
-{
- unsigned pos, q, r;
- dnode_secno dno;
- struct hpfs_dirent *de;
-
- /*
- * Get the position code and split off the rightmost index r
- */
-
- pos = *posp;
- q = pos >> 6;
- r = pos & 077;
-
- /*
- * Get the sector address of the dnode
- * pointed to by the leading part q
- */
-
- dno = dir_subdno(inode, q);
- if (!dno)
- return 0;
-
- /*
- * Get the entry at index r in dnode q
- */
-
- de = map_nth_dirent(inode->i_dev, dno, r, qbh);
-
- /*
- * If none, we're out of files in this dnode. Ascend.
- */
-
- if (!de) {
- if (q == 0)
- return 0;
- *posp = q + 1;
- return map_pos_dirent(inode, posp, qbh);
- }
-
- /*
- * If a subtree is here, descend.
- */
-
- if (de->down)
- *posp = pos << 6 | 1;
- else
- *posp = pos + 1;
-
- /*
- * Don't return the ^A^A and \377 entries.
- */
-
- if (de->first || de->last) {
- brelse4(qbh);
- return map_pos_dirent(inode, posp, qbh);
- }
- else
- return de;
-}
-
-/*
- * Return the address of the dnode with subtree coordinates given by pos.
- */
-
-static dnode_secno dir_subdno(struct inode *inode, unsigned pos)
-{
- struct hpfs_dirent *de;
- struct quad_buffer_head qbh;
-
- /*
- * 0 is the root dnode
- */
-
- if (pos == 0)
- return inode->i_hpfs_dno;
-
- /*
- * we have one pos->dnode translation cached in the inode
- */
-
- else if (pos == inode->i_hpfs_dpos)
- return inode->i_hpfs_dsubdno;
-
- /*
- * otherwise go look
- */
-
- else {
- unsigned q = pos >> 6;
- unsigned r = pos & 077;
- dnode_secno dno;
-
- /*
- * dnode at position q
- */
- dno = dir_subdno(inode, q);
- if (dno == 0)
- return 0;
-
- /*
- * entry at index r
- */
- de = map_nth_dirent(inode->i_dev, dno, r, &qbh);
- if (!de || !de->down)
- return 0;
-
- /*
- * get the dnode down pointer
- */
- dno = de_down_pointer(de);
- brelse4(&qbh);
-
- /*
- * cache it for next time
- */
- inode->i_hpfs_dpos = pos;
- inode->i_hpfs_dsubdno = dno;
- return dno;
- }
-}
-
-/*
- * Return the dir entry at index n in dnode dno, or 0 if there isn't one
- */
-
-static struct hpfs_dirent *map_nth_dirent(kdev_t dev, dnode_secno dno,
- int n,
- struct quad_buffer_head *qbh)
-{
- int i;
- struct hpfs_dirent *de, *de_end;
- struct dnode *dnode = map_dnode(dev, dno, qbh);
-
- de = dnode_first_de(dnode);
- de_end = dnode_end_de(dnode);
-
- for (i = 1; de < de_end; i++, de = de_next_de(de)) {
- if (i == n)
- return de;
- if (de->last || de->length == 0)
- break;
- }
-
- brelse4(qbh);
- return 0;
-}
-
-static ssize_t hpfs_dir_read(struct file *filp, char *buf,
- size_t count, loff_t *ppos)
-{
- return -EISDIR;
-}
-
-/* Return the dnode pointer in a directory fnode */
-
-static dnode_secno fnode_dno(kdev_t dev, ino_t ino)
-{
- struct buffer_head *bh;
- struct fnode *fnode;
- dnode_secno dno;
-
- fnode = map_fnode(dev, ino, &bh);
- if (!fnode)
- return 0;
-
- dno = fnode->u.external[0].disk_secno;
- brelse(bh);
- return dno;
-}
-
-/* Map an fnode into a buffer and return pointers to it and to the buffer. */
-
-static struct fnode *map_fnode(kdev_t dev, ino_t ino, struct buffer_head **bhp)
-{
- struct fnode *fnode;
-
- if (ino == 0) {
- printk("HPFS: missing fnode\n");
- return 0;
- }
-
- fnode = map_sector(dev, ino_secno(ino), bhp);
- if (fnode)
- if (fnode->magic != FNODE_MAGIC) {
- printk("HPFS: map_fnode: bad fnode pointer\n");
- brelse(*bhp);
- return 0;
- }
- return fnode;
-}
-
-/* Map an anode into a buffer and return pointers to it and to the buffer. */
-
-static struct anode *map_anode(kdev_t dev, unsigned secno,
- struct buffer_head **bhp)
-{
- struct anode *anode;
-
- if (secno == 0) {
- printk("HPFS: missing anode\n");
- return 0;
- }
-
- anode = map_sector(dev, secno, bhp);
- if (anode)
- if (anode->magic != ANODE_MAGIC || anode->self != secno) {
- printk("HPFS: map_anode: bad anode pointer\n");
- brelse(*bhp);
- return 0;
- }
- return anode;
-}
-
-/* Map a dnode into a buffer and return pointers to it and to the buffer. */
-
-static struct dnode *map_dnode(kdev_t dev, unsigned secno,
- struct quad_buffer_head *qbh)
-{
- struct dnode *dnode;
-
- if (secno == 0) {
- printk("HPFS: missing dnode\n");
- return 0;
- }
-
- dnode = map_4sectors(dev, secno, qbh);
- if (dnode)
- if (dnode->magic != DNODE_MAGIC || dnode->self != secno) {
- printk("HPFS: map_dnode: bad dnode pointer\n");
- brelse4(qbh);
- return 0;
- }
- return dnode;
-}
-
-/* Map a sector into a buffer and return pointers to it and to the buffer. */
-
-static void *map_sector(kdev_t dev, unsigned secno, struct buffer_head **bhp)
-{
- struct buffer_head *bh;
-
- if ((*bhp = bh = bread(dev, secno, 512)) != 0)
- return bh->b_data;
- else {
- printk("HPFS: map_sector: read error\n");
- return 0;
- }
-}
-
-/* Map 4 sectors into a 4buffer and return pointers to it and to the buffer. */
-
-static void *map_4sectors(kdev_t dev, unsigned secno,
- struct quad_buffer_head *qbh)
-{
- struct buffer_head *bh;
- char *data;
-
- if (secno & 3) {
- printk("HPFS: map_4sectors: unaligned read\n");
- return 0;
- }
-
- qbh->data = data = kmalloc(2048, GFP_KERNEL);
- if (!data)
- goto bail;
-
- qbh->bh[0] = bh = bread(dev, secno, 512);
- if (!bh)
- goto bail0;
- memcpy(data, bh->b_data, 512);
-
- qbh->bh[1] = bh = bread(dev, secno + 1, 512);
- if (!bh)
- goto bail1;
- memcpy(data + 512, bh->b_data, 512);
-
- qbh->bh[2] = bh = bread(dev, secno + 2, 512);
- if (!bh)
- goto bail2;
- memcpy(data + 2 * 512, bh->b_data, 512);
-
- qbh->bh[3] = bh = bread(dev, secno + 3, 512);
- if (!bh)
- goto bail3;
- memcpy(data + 3 * 512, bh->b_data, 512);
-
- return data;
-
- bail3:
- brelse(qbh->bh[2]);
- bail2:
- brelse(qbh->bh[1]);
- bail1:
- brelse(qbh->bh[0]);
- bail0:
- kfree_s(data, 2048);
- bail:
- printk("HPFS: map_4sectors: read error\n");
- return 0;
-}
-
-/* Deallocate a 4-buffer block */
-
-static void brelse4(struct quad_buffer_head *qbh)
-{
- brelse(qbh->bh[3]);
- brelse(qbh->bh[2]);
- brelse(qbh->bh[1]);
- brelse(qbh->bh[0]);
- kfree_s(qbh->data, 2048);
-}
-
-static struct file_system_type hpfs_fs_type = {
- "hpfs",
- FS_REQUIRES_DEV,
- hpfs_read_super,
- NULL
-};
-
-__initfunc(int init_hpfs_fs(void))
-{
- return register_filesystem(&hpfs_fs_type);
-}
-
-#ifdef MODULE
-EXPORT_NO_SYMBOLS;
-
-int init_module(void)
-{
- return init_hpfs_fs();
-}
-
-void cleanup_module(void)
-{
- unregister_filesystem(&hpfs_fs_type);
-}
-
-#endif