diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-06-21 22:16:05 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-06-21 22:16:05 +0000 |
commit | 73ed328f3a698087551b4d6a36196b0819bc38af (patch) | |
tree | d0907f2e7e5f36ea0808ed6b1f10c5caf51478a5 /fs | |
parent | 89a61cd744a621efff2a4d7f0d99258f850338f2 (diff) |
Cleanup, sync with others sources.
Diffstat (limited to 'fs')
-rw-r--r-- | fs/Config.in | 1 | ||||
-rw-r--r-- | fs/hpfs/hpfs_caps.c | 171 | ||||
-rw-r--r-- | fs/hpfs/hpfs_caps.h | 4 | ||||
-rw-r--r-- | fs/hpfs/hpfs_fs.c | 1759 |
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 |