summaryrefslogtreecommitdiffstats
path: root/fs/xiafs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1994-11-28 11:59:19 +0000
committer <ralf@linux-mips.org>1994-11-28 11:59:19 +0000
commit1513ff9b7899ab588401c89db0e99903dbf5f886 (patch)
treef69cc81a940a502ea23d664c3ffb2d215a479667 /fs/xiafs
Import of Linus's Linux 1.1.68
Diffstat (limited to 'fs/xiafs')
-rw-r--r--fs/xiafs/Makefile31
-rw-r--r--fs/xiafs/bitmap.c388
-rw-r--r--fs/xiafs/dir.c135
-rw-r--r--fs/xiafs/file.c252
-rw-r--r--fs/xiafs/fsync.c159
-rw-r--r--fs/xiafs/inode.c502
-rw-r--r--fs/xiafs/namei.c848
-rw-r--r--fs/xiafs/symlink.c118
-rw-r--r--fs/xiafs/truncate.c197
-rw-r--r--fs/xiafs/xiafs_mac.h32
10 files changed, 2662 insertions, 0 deletions
diff --git a/fs/xiafs/Makefile b/fs/xiafs/Makefile
new file mode 100644
index 000000000..097563244
--- /dev/null
+++ b/fs/xiafs/Makefile
@@ -0,0 +1,31 @@
+#
+# Makefile for the XIAFS filesystem routines.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.c.s:
+ $(CC) $(CFLAGS) -S $<
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+.s.o:
+ $(AS) -o $*.o $<
+
+OBJS= bitmap.o truncate.o namei.o inode.o \
+ file.o dir.o symlink.o fsync.o
+
+xiafs.o: $(OBJS)
+ $(LD) -r -o xiafs.o $(OBJS)
+
+dep:
+ $(CPP) -M *.c > .depend
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/fs/xiafs/bitmap.c b/fs/xiafs/bitmap.c
new file mode 100644
index 000000000..4dee5cfbb
--- /dev/null
+++ b/fs/xiafs/bitmap.c
@@ -0,0 +1,388 @@
+/*
+ * linux/fs/xiafs/bitmap.c
+ *
+ * Copyright (C) Q. Frank Xia, 1993.
+ *
+ * Based on Linus' minix/bitmap.c
+ * Copyright (C) Linus Torvalds, 1991, 1992.
+ *
+ * This software may be redistributed per Linux Copyright.
+ */
+
+/* bitmap.c contains the code that handles the inode and block bitmaps */
+
+#include <linux/sched.h>
+#include <linux/locks.h>
+#include <linux/xia_fs.h>
+#include <linux/stat.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/bitops.h>
+
+#include "xiafs_mac.h"
+
+
+char internal_error_message[]="XIA-FS: internal error %s %d\n";
+
+static int find_first_zero(struct buffer_head *bh, int start_bit, int end_bit)
+{
+ /* This routine searches first 0 bit from (start_bit) to (end_bit-1).
+ * If found the bit is set to 1 and the bit # is returned, otherwise,
+ * -1 is returned. Race condition is avoid by using "btsl" and
+ * "goto repeat". ---Frank.
+ */
+
+ int end, i, j, tmp;
+ u_long *bmap;
+
+ bmap=(u_long *)bh->b_data;
+ end = end_bit >> 5;
+
+repeat:
+ i=start_bit >> 5;
+ if ( (tmp=(~bmap[i]) & (0xffffffff << (start_bit & 31))) )
+ goto zone_found;
+ while (++i < end)
+ if (~bmap[i]) {
+ tmp=~bmap[i];
+ goto zone_found;
+ }
+ if ( !(tmp=~bmap[i] & ((1 << (end_bit & 31)) -1)) )
+ return -1;
+zone_found:
+ for (j=0; j < 32; j++)
+ if (tmp & (1 << j))
+ break;
+ if (set_bit(j,bmap+i)) {
+ start_bit=j + (i << 5) + 1;
+ goto repeat;
+ }
+ mark_buffer_dirty(bh, 1);
+ return j + (i << 5);
+}
+
+static void clear_buf(struct buffer_head * bh)
+{
+ register int i;
+ register long * lp;
+
+ lp=(long *)bh->b_data;
+ for (i= bh->b_size >> 2; i-- > 0; )
+ *lp++=0;
+}
+
+static void que(struct buffer_head * bmap[], int bznr[], int pos)
+{
+ struct buffer_head * tbh;
+ int tmp;
+ int i;
+
+ tbh=bmap[pos];
+ tmp=bznr[pos];
+ for (i=pos; i > 0; i--) {
+ bmap[i]=bmap[i-1];
+ bznr[i]=bznr[i-1];
+ }
+ bmap[0]=tbh;
+ bznr[0]=tmp;
+}
+
+#define get_imap_zone(sb, bit_nr, not_que) \
+ get__map_zone((sb), (sb)->u.xiafs_sb.s_imap_buf, \
+ (sb)->u.xiafs_sb.s_imap_iznr, \
+ (sb)->u.xiafs_sb.s_imap_cached, 1, \
+ (sb)->u.xiafs_sb.s_imap_zones, _XIAFS_IMAP_SLOTS, \
+ bit_nr, not_que)
+
+#define get_zmap_zone(sb, bit_nr, not_que) \
+ get__map_zone((sb), (sb)->u.xiafs_sb.s_zmap_buf, \
+ (sb)->u.xiafs_sb.s_zmap_zznr, \
+ (sb)->u.xiafs_sb.s_zmap_cached, \
+ 1+(sb)->u.xiafs_sb.s_imap_zones, \
+ (sb)->u.xiafs_sb.s_zmap_zones, _XIAFS_ZMAP_SLOTS, \
+ bit_nr, not_que)
+
+static struct buffer_head *
+get__map_zone(struct super_block *sb, struct buffer_head * bmap_buf[],
+ int bznr[], u_char cache, int first_zone,
+ int bmap_zones, int slots, u_long bit_nr, int * not_que)
+{
+ struct buffer_head * tmp_bh;
+ int z_nr, i;
+
+ z_nr = bit_nr >> XIAFS_BITS_PER_Z_BITS(sb);
+ if (z_nr >= bmap_zones) {
+ printk("XIA-FS: bad inode/zone number (%s %d)\n", WHERE_ERR);
+ return NULL;
+ }
+ if (!cache)
+ return bmap_buf[z_nr];
+ lock_super(sb);
+ for (i=0; i < slots; i++)
+ if (bznr[i]==z_nr)
+ break;
+ if (i < slots) { /* cache hit */
+ if (not_que) {
+ *not_que=i;
+ return bmap_buf[i];
+ } else {
+ que(bmap_buf, bznr, i);
+ return bmap_buf[0];
+ }
+ }
+ tmp_bh=bread(sb->s_dev, z_nr+first_zone, XIAFS_ZSIZE(sb)); /* cache not hit */
+ if (!tmp_bh) {
+ printk("XIA-FS: read bitmap failed (%s %d)\n", WHERE_ERR);
+ unlock_super(sb);
+ return NULL;
+ }
+ brelse(bmap_buf[slots-1]);
+ bmap_buf[slots-1]=tmp_bh;
+ bznr[slots-1]=z_nr;
+ if (not_que)
+ *not_que=slots-1;
+ else
+ que(bmap_buf, bznr, slots-1);
+ return tmp_bh;
+}
+
+#define xiafs_unlock_super(sb, cache) if (cache) unlock_super(sb);
+
+#define get_free_ibit(sb, prev_bit) \
+ get_free__bit(sb, sb->u.xiafs_sb.s_imap_buf, \
+ sb->u.xiafs_sb.s_imap_iznr, \
+ sb->u.xiafs_sb.s_imap_cached, \
+ 1, sb->u.xiafs_sb.s_imap_zones, \
+ _XIAFS_IMAP_SLOTS, prev_bit);
+
+#define get_free_zbit(sb, prev_bit) \
+ get_free__bit(sb, sb->u.xiafs_sb.s_zmap_buf, \
+ sb->u.xiafs_sb.s_zmap_zznr, \
+ sb->u.xiafs_sb.s_zmap_cached, \
+ 1 + sb->u.xiafs_sb.s_imap_zones, \
+ sb->u.xiafs_sb.s_zmap_zones, \
+ _XIAFS_ZMAP_SLOTS, prev_bit);
+
+static u_long
+get_free__bit(struct super_block *sb, struct buffer_head * bmap_buf[],
+ int bznr[], u_char cache, int first_zone, int bmap_zones,
+ int slots, u_long prev_bit)
+{
+ struct buffer_head * bh;
+ int not_done=0;
+ u_long pos, start_bit, end_bit, total_bits;
+ int z_nr, tmp;
+
+ total_bits=bmap_zones << XIAFS_BITS_PER_Z_BITS(sb);
+ if (prev_bit >= total_bits)
+ prev_bit=0;
+ pos=prev_bit+1;
+ end_bit=XIAFS_BITS_PER_Z(sb);
+
+ do {
+ if (pos >= total_bits)
+ pos=0;
+ if (!not_done) { /* first time */
+ not_done=1;
+ start_bit= pos & (end_bit-1);
+ } else
+ start_bit=0;
+ if ( pos < prev_bit && pos+end_bit >= prev_bit) { /* last time */
+ not_done=0;
+ end_bit=prev_bit & (end_bit-1); /* only here end_bit modified */
+ }
+ bh = get__map_zone(sb, bmap_buf, bznr, cache, first_zone,
+ bmap_zones, slots, pos, &z_nr);
+ if (!bh)
+ return 0;
+ tmp=find_first_zero(bh, start_bit, end_bit);
+ if (tmp >= 0)
+ break;
+ xiafs_unlock_super(sb, sb->u.xiafs_sb.s_zmap_cached);
+ pos=(pos & ~(end_bit-1))+end_bit;
+ } while (not_done);
+
+ if (tmp < 0)
+ return 0;
+ if (cache)
+ que(bmap_buf, bznr, z_nr);
+ xiafs_unlock_super(sb, cache);
+ return (pos & ~(XIAFS_BITS_PER_Z(sb)-1))+tmp;
+}
+
+void xiafs_free_zone(struct super_block * sb, int d_addr)
+{
+ struct buffer_head * bh;
+ unsigned int bit, offset;
+
+ if (!sb) {
+ printk(INTERN_ERR);
+ return;
+ }
+ if (d_addr < sb->u.xiafs_sb.s_firstdatazone ||
+ d_addr >= sb->u.xiafs_sb.s_nzones) {
+ printk("XIA-FS: bad zone number (%s %d)\n", WHERE_ERR);
+ return;
+ }
+ bh = get_hash_table(sb->s_dev, d_addr, XIAFS_ZSIZE(sb));
+ if (bh)
+ bh->b_dirt=0;
+ brelse(bh);
+ bit=d_addr - sb->u.xiafs_sb.s_firstdatazone + 1;
+ bh = get_zmap_zone(sb, bit, NULL);
+ if (!bh)
+ return;
+ offset = bit & (XIAFS_BITS_PER_Z(sb) -1);
+ if (!clear_bit(offset, bh->b_data))
+ printk("XIA-FS: dev %04x"
+ " block bit %u (0x%x) already cleared (%s %d)\n",
+ sb->s_dev, bit, bit, WHERE_ERR);
+ mark_buffer_dirty(bh, 1);
+ xiafs_unlock_super(sb, sb->u.xiafs_sb.s_zmap_cached);
+}
+
+int xiafs_new_zone(struct super_block * sb, u_long prev_addr)
+{
+ struct buffer_head * bh;
+ int prev_znr, tmp;
+
+ if (!sb) {
+ printk(INTERN_ERR);
+ return 0;
+ }
+ if (prev_addr < sb->u.xiafs_sb.s_firstdatazone ||
+ prev_addr >= sb->u.xiafs_sb.s_nzones) {
+ prev_addr=sb->u.xiafs_sb.s_firstdatazone;
+ }
+ prev_znr=prev_addr-sb->u.xiafs_sb.s_firstdatazone+1;
+ tmp=get_free_zbit(sb, prev_znr);
+ if (!tmp)
+ return 0;
+ tmp += sb->u.xiafs_sb.s_firstdatazone -1;
+ if (!(bh = getblk(sb->s_dev, tmp, XIAFS_ZSIZE(sb)))) {
+ printk("XIA-FS: I/O error (%s %d)\n", WHERE_ERR);
+ return 0;
+ }
+ if (bh->b_count != 1) {
+ printk(INTERN_ERR);
+ return 0;
+ }
+ clear_buf(bh);
+ bh->b_uptodate = 1;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ return tmp;
+}
+
+void xiafs_free_inode(struct inode * inode)
+{
+ struct buffer_head * bh;
+ struct super_block * sb;
+ unsigned long ino;
+
+ if (!inode)
+ return;
+ if (!inode->i_dev || inode->i_count!=1 || inode->i_nlink || !inode->i_sb ||
+ inode->i_ino < 3 || inode->i_ino > inode->i_sb->u.xiafs_sb.s_ninodes) {
+ printk("XIA-FS: bad inode (%s %d)\n", WHERE_ERR);
+ return;
+ }
+ sb = inode->i_sb;
+ ino = inode->i_ino;
+ bh = get_imap_zone(sb, ino, NULL);
+ if (!bh)
+ return;
+ clear_inode(inode);
+ if (!clear_bit(ino & (XIAFS_BITS_PER_Z(sb)-1), bh->b_data))
+ printk("XIA-FS: dev %04x"
+ "inode bit %ld (0x%lx) already cleared (%s %d)\n",
+ inode->i_dev, ino, ino, WHERE_ERR);
+ mark_buffer_dirty(bh, 1);
+ xiafs_unlock_super(sb, sb->u.xiafs_sb.s_imap_cached);
+}
+
+struct inode * xiafs_new_inode(struct inode * dir)
+{
+ struct super_block * sb;
+ struct inode * inode;
+ ino_t tmp;
+
+ sb = dir->i_sb;
+ if (!dir || !(inode = get_empty_inode()))
+ return NULL;
+ inode->i_sb = sb;
+ inode->i_flags = inode->i_sb->s_flags;
+
+ tmp=get_free_ibit(sb, dir->i_ino);
+ if (!tmp) {
+ iput(inode);
+ return NULL;
+ }
+ inode->i_count = 1;
+ inode->i_nlink = 1;
+ inode->i_dev = sb->s_dev;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
+ inode->i_dirt = 1;
+ inode->i_ino = tmp;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_op = NULL;
+ inode->i_blocks = 0;
+ inode->i_blksize = XIAFS_ZSIZE(inode->i_sb);
+ insert_inode_hash(inode);
+ return inode;
+}
+
+static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
+
+static u_long count_zone(struct buffer_head * bh)
+{
+ int i, tmp;
+ u_long sum;
+
+ sum=0;
+ for (i=bh->b_size; i-- > 0; ) {
+ tmp=bh->b_data[i];
+ sum += nibblemap[tmp & 0xf] + nibblemap[(tmp & 0xff) >> 4];
+ }
+ return sum;
+}
+
+unsigned long xiafs_count_free_inodes(struct super_block *sb)
+{
+ struct buffer_head * bh;
+ int izones, i, not_que;
+ u_long sum;
+
+ sum=0;
+ izones=sb->u.xiafs_sb.s_imap_zones;
+ for (i=0; i < izones; i++) {
+ bh=get_imap_zone(sb, i << XIAFS_BITS_PER_Z_BITS(sb), &not_que);
+ if (bh) {
+ sum += count_zone(bh);
+ xiafs_unlock_super(sb, sb->u.xiafs_sb.s_imap_cached);
+ }
+ }
+ i=izones << XIAFS_BITS_PER_Z_BITS(sb);
+ return i - sum;
+}
+
+unsigned long xiafs_count_free_zones(struct super_block *sb)
+{
+ struct buffer_head * bh;
+ int zzones, i, not_que;
+ u_long sum;
+
+ sum=0;
+ zzones=sb->u.xiafs_sb.s_zmap_zones;
+ for (i=0; i < zzones; i++) {
+ bh=get_zmap_zone(sb, i << XIAFS_BITS_PER_Z_BITS(sb), &not_que);
+ if (bh) {
+ sum += count_zone(bh);
+ xiafs_unlock_super(sb, sb->u.xiafs_sb.s_zmap_cached);
+ }
+ }
+ i=zzones << XIAFS_BITS_PER_Z_BITS(sb);
+ return i - sum;
+}
diff --git a/fs/xiafs/dir.c b/fs/xiafs/dir.c
new file mode 100644
index 000000000..d9db56ddc
--- /dev/null
+++ b/fs/xiafs/dir.c
@@ -0,0 +1,135 @@
+/*
+ * linux/fs/xiafs/dir.c
+ *
+ * Copyright (C) Q. Frank Xia, 1993.
+ *
+ * Based on Linus' minix/dir.c
+ * Copyright (C) Linus Torvalds, 1991, 1992.
+ *
+ * This software may be redistributed per Linux Copyright.
+ */
+
+#include <asm/segment.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/xia_fs.h>
+#include <linux/stat.h>
+
+#include "xiafs_mac.h"
+
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+3) & ~3)
+
+static int xiafs_dir_read(struct inode *, struct file *, char *, int);
+static int xiafs_readdir(struct inode *, struct file *, struct dirent *, int);
+
+static struct file_operations xiafs_dir_operations = {
+ NULL, /* lseek - default */
+ xiafs_dir_read, /* read */
+ NULL, /* write - bad */
+ xiafs_readdir, /* readdir */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ NULL, /* mmap */
+ NULL, /* no special open code */
+ NULL, /* no special release code */
+ file_fsync /* default fsync */
+};
+
+/*
+ * directories can handle most operations...
+ */
+struct inode_operations xiafs_dir_inode_operations = {
+ &xiafs_dir_operations, /* default directory file-ops */
+ xiafs_create, /* create */
+ xiafs_lookup, /* lookup */
+ xiafs_link, /* link */
+ xiafs_unlink, /* unlink */
+ xiafs_symlink, /* symlink */
+ xiafs_mkdir, /* mkdir */
+ xiafs_rmdir, /* rmdir */
+ xiafs_mknod, /* mknod */
+ xiafs_rename, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* bmap */
+ xiafs_truncate, /* truncate */
+ NULL /* permission */
+};
+
+static int xiafs_dir_read(struct inode * inode,
+ struct file * filp, char * buf, int count)
+{
+ return -EISDIR;
+}
+
+static int xiafs_readdir(struct inode * inode,
+ struct file * filp, struct dirent * dirent, int count)
+{
+ u_int offset, i,ret;
+ struct buffer_head * bh;
+ struct xiafs_direct * de;
+
+ if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode))
+ return -EBADF;
+ if (inode->i_size & (XIAFS_ZSIZE(inode->i_sb) - 1) )
+ return -EBADF;
+ ret = 0;
+ while (!ret && filp->f_pos < inode->i_size) {
+ offset = filp->f_pos & (XIAFS_ZSIZE(inode->i_sb) - 1);
+ bh = xiafs_bread(inode, filp->f_pos >> XIAFS_ZSIZE_BITS(inode->i_sb),0);
+ if (!bh) {
+ filp->f_pos += XIAFS_ZSIZE(inode->i_sb)-offset;
+ continue;
+ }
+ for (i = 0; i < XIAFS_ZSIZE(inode->i_sb) && i < offset; ) {
+ de = (struct xiafs_direct *) (bh->b_data + i);
+ if (!de->d_rec_len)
+ break;
+ i += de->d_rec_len;
+ }
+ offset = i;
+ de = (struct xiafs_direct *) (offset + bh->b_data);
+
+ while (!ret && offset < XIAFS_ZSIZE(inode->i_sb) && filp->f_pos < inode->i_size) {
+ if (de->d_ino > inode->i_sb->u.xiafs_sb.s_ninodes ||
+ de->d_rec_len < 12 ||
+ (char *)de+de->d_rec_len > XIAFS_ZSIZE(inode->i_sb)+bh->b_data ||
+ de->d_name_len < 1 || de->d_name_len + 8 > de->d_rec_len ||
+ de->d_name_len > _XIAFS_NAME_LEN ||
+ de->d_name[de->d_name_len] ) {
+ printk("XIA-FS: bad directory entry (%s %d)\n", WHERE_ERR);
+ brelse(bh);
+ return 0;
+ }
+ offset += de->d_rec_len;
+ filp->f_pos += de->d_rec_len;
+ if (de->d_ino) {
+ for (i = 0; i < de->d_name_len ; i++)
+ put_fs_byte(de->d_name[i],i+dirent->d_name);
+ put_fs_byte(0,i+dirent->d_name);
+ put_fs_long(de->d_ino,&dirent->d_ino);
+ put_fs_word(i,&dirent->d_reclen);
+ if (!IS_RDONLY (inode)) {
+ inode->i_atime=CURRENT_TIME;
+ inode->i_dirt=1;
+ }
+ ret = ROUND_UP(NAME_OFFSET(dirent)+i+1);
+ break;
+ }
+ de = (struct xiafs_direct *) (offset + bh->b_data);
+ }
+ brelse(bh);
+ if (offset > XIAFS_ZSIZE(inode->i_sb)) {
+ printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
+ return 0;
+ }
+ }
+ if (!IS_RDONLY (inode)) {
+ inode->i_atime=CURRENT_TIME;
+ inode->i_dirt=1;
+ }
+ return ret;
+}
diff --git a/fs/xiafs/file.c b/fs/xiafs/file.c
new file mode 100644
index 000000000..5678ffd0b
--- /dev/null
+++ b/fs/xiafs/file.c
@@ -0,0 +1,252 @@
+/*
+ * linux/fs/xiafs/file.c
+ *
+ * Copyright (C) Q. Frank Xia, 1993.
+ *
+ * Based on Linus' minix/file.c
+ * Copyright (C) Linus Torvalds, 1991, 1992.
+ *
+ * This software may be redistributed per Linux Copyright.
+ */
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/xia_fs.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/locks.h>
+
+#include "xiafs_mac.h"
+
+#define NBUF 32
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+static int xiafs_file_read(struct inode *, struct file *, char *, int);
+static int xiafs_file_write(struct inode *, struct file *, char *, int);
+
+/*
+ * We have mostly NULL's here: the current defaults are ok for
+ * the xiafs filesystem.
+ */
+static struct file_operations xiafs_file_operations = {
+ NULL, /* lseek - default */
+ xiafs_file_read, /* read */
+ xiafs_file_write, /* write */
+ NULL, /* readdir - bad */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ generic_mmap, /* mmap */
+ NULL, /* no special open is needed */
+ NULL, /* release */
+ xiafs_sync_file /* fsync */
+};
+
+struct inode_operations xiafs_file_inode_operations = {
+ &xiafs_file_operations, /* 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 */
+ xiafs_bmap, /* bmap */
+ xiafs_truncate, /* truncate */
+ NULL /* permission */
+};
+
+static int
+xiafs_file_read(struct inode * inode, struct file * filp, char * buf, int count)
+{
+ int read, left, chars;
+ int zone_nr, zones, f_zones, offset;
+ int bhrequest, uptodate;
+ struct buffer_head ** bhb, ** bhe;
+ struct buffer_head * bhreq[NBUF];
+ struct buffer_head * buflist[NBUF];
+
+ if (!inode) {
+ printk("XIA-FS: inode = NULL (%s %d)\n", WHERE_ERR);
+ return -EINVAL;
+ }
+ if (!S_ISREG(inode->i_mode)) {
+ printk("XIA-FS: mode != regular (%s %d)\n", WHERE_ERR);
+ return -EINVAL;
+ }
+ offset = filp->f_pos;
+ left = inode->i_size - offset;
+ if (left > count)
+ left = count;
+ if (left <= 0)
+ return 0;
+ read = 0;
+ zone_nr = offset >> XIAFS_ZSIZE_BITS(inode->i_sb);
+ offset &= XIAFS_ZSIZE(inode->i_sb) -1 ;
+ f_zones =(inode->i_size+XIAFS_ZSIZE(inode->i_sb)-1)>>XIAFS_ZSIZE_BITS(inode->i_sb);
+ zones = (left+offset+XIAFS_ZSIZE(inode->i_sb)-1) >> XIAFS_ZSIZE_BITS(inode->i_sb);
+ bhb = bhe = buflist;
+ if (filp->f_reada) {
+ if(zones < read_ahead[MAJOR(inode->i_dev)] >> (1+XIAFS_ZSHIFT(inode->i_sb)))
+ zones = read_ahead[MAJOR(inode->i_dev)] >> (1+XIAFS_ZSHIFT(inode->i_sb));
+ if (zone_nr + zones > f_zones)
+ zones = f_zones - zone_nr;
+ }
+
+ /* We do this in a two stage process. We first try and request
+ as many blocks as we can, then we wait for the first one to
+ complete, and then we try and wrap up as many as are actually
+ done. This routine is rather generic, in that it can be used
+ in a filesystem by substituting the appropriate function in
+ for getblk.
+
+ This routine is optimized to make maximum use of the various
+ buffers and caches. */
+
+ do {
+ bhrequest = 0;
+ uptodate = 1;
+ while (zones--) {
+ *bhb = xiafs_getblk(inode, zone_nr++, 0);
+ if (*bhb && !(*bhb)->b_uptodate) {
+ uptodate = 0;
+ bhreq[bhrequest++] = *bhb;
+ }
+
+ if (++bhb == &buflist[NBUF])
+ bhb = buflist;
+
+ /* If the block we have on hand is uptodate, go ahead
+ and complete processing. */
+ if (uptodate)
+ break;
+ if (bhb == bhe)
+ break;
+ }
+
+ /* Now request them all */
+ if (bhrequest)
+ ll_rw_block(READ, bhrequest, bhreq);
+
+ do { /* Finish off all I/O that has actually completed */
+ if (*bhe) {
+ wait_on_buffer(*bhe);
+ if (!(*bhe)->b_uptodate) { /* read error? */
+ brelse(*bhe);
+ if (++bhe == &buflist[NBUF])
+ bhe = buflist;
+ left = 0;
+ break;
+ }
+ }
+ if (left < XIAFS_ZSIZE(inode->i_sb) - offset)
+ chars = left;
+ else
+ chars = XIAFS_ZSIZE(inode->i_sb) - offset;
+ filp->f_pos += chars;
+ left -= chars;
+ read += chars;
+ if (*bhe) {
+ memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
+ brelse(*bhe);
+ buf += chars;
+ } else {
+ while (chars-->0)
+ put_fs_byte(0,buf++);
+ }
+ offset = 0;
+ if (++bhe == &buflist[NBUF])
+ bhe = buflist;
+ } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
+ } while (left > 0);
+
+/* Release the read-ahead blocks */
+ while (bhe != bhb) {
+ brelse(*bhe);
+ if (++bhe == &buflist[NBUF])
+ bhe = buflist;
+ };
+ if (!read)
+ return -EIO;
+ filp->f_reada = 1;
+ if (!IS_RDONLY (inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
+ return read;
+}
+
+static int
+xiafs_file_write(struct inode * inode, struct file * filp, char * buf, int count)
+{
+ off_t pos;
+ int written, c;
+ struct buffer_head * bh;
+ char * cp;
+
+ if (!inode) {
+ printk("XIA-FS: inode = NULL (%s %d)\n", WHERE_ERR);
+ return -EINVAL;
+ }
+ if (!S_ISREG(inode->i_mode)) {
+ printk("XIA-FS: mode != regular (%s %d)\n", WHERE_ERR);
+ return -EINVAL;
+ }
+/*
+ * ok, append may not work when many processes are writing at the same time
+ * but so what. That way leads to madness anyway.
+ */
+ if (filp->f_flags & O_APPEND)
+ pos = inode->i_size;
+ else
+ pos = filp->f_pos;
+ written = 0;
+ while (written < count) {
+ bh = xiafs_getblk(inode, pos >> XIAFS_ZSIZE_BITS(inode->i_sb), 1);
+ if (!bh) {
+ if (!written)
+ written = -ENOSPC;
+ break;
+ }
+ c = XIAFS_ZSIZE(inode->i_sb) - (pos & (XIAFS_ZSIZE(inode->i_sb) - 1));
+ if (c > count-written)
+ c = count-written;
+ if (c != XIAFS_ZSIZE(inode->i_sb) && !bh->b_uptodate) {
+ ll_rw_block(READ, 1, &bh);
+ wait_on_buffer(bh);
+ if (!bh->b_uptodate) {
+ brelse(bh);
+ if (!written)
+ written = -EIO;
+ break;
+ }
+ }
+ cp = (pos & (XIAFS_ZSIZE(inode->i_sb)-1)) + bh->b_data;
+ pos += c;
+ if (pos > inode->i_size) {
+ inode->i_size = pos;
+ inode->i_dirt = 1;
+ }
+ written += c;
+ memcpy_fromfs(cp,buf,c);
+ buf += c;
+ bh->b_uptodate = 1;
+ mark_buffer_dirty(bh, 0);
+ brelse(bh);
+ }
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ filp->f_pos = pos;
+ inode->i_dirt = 1;
+
+ return written;
+}
diff --git a/fs/xiafs/fsync.c b/fs/xiafs/fsync.c
new file mode 100644
index 000000000..67681b2c6
--- /dev/null
+++ b/fs/xiafs/fsync.c
@@ -0,0 +1,159 @@
+/*
+ * linux/fs/xiafs/fsync.c
+ *
+ * Changes Copyright (C) 1993 Stephen Tweedie (sct@dcs.ed.ac.uk)
+ * from
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * xiafs fsync primitive
+ */
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/locks.h>
+
+#include <linux/fs.h>
+#include <linux/xia_fs.h>
+
+#include "xiafs_mac.h"
+
+
+#define blocksize (XIAFS_ZSIZE(inode->i_sb))
+#define addr_per_block (XIAFS_ADDRS_PER_Z(inode->i_sb))
+
+static int sync_block (struct inode * inode, unsigned long * block, int wait)
+{
+ struct buffer_head * bh;
+ int tmp;
+
+ if (!*block)
+ return 0;
+ tmp = *block;
+ bh = get_hash_table(inode->i_dev, *block, blocksize);
+ if (!bh)
+ return 0;
+ if (*block != tmp) {
+ brelse (bh);
+ return 1;
+ }
+ if (wait && bh->b_req && !bh->b_uptodate) {
+ brelse(bh);
+ return -1;
+ }
+ if (wait || !bh->b_uptodate || !bh->b_dirt)
+ {
+ brelse(bh);
+ return 0;
+ }
+ ll_rw_block(WRITE, 1, &bh);
+ bh->b_count--;
+ return 0;
+}
+
+static int sync_iblock (struct inode * inode, unsigned long * iblock,
+ struct buffer_head **bh, int wait)
+{
+ int rc, tmp;
+
+ *bh = NULL;
+ tmp = *iblock;
+ if (!tmp)
+ return 0;
+ rc = sync_block (inode, iblock, wait);
+ if (rc)
+ return rc;
+ *bh = bread(inode->i_dev, tmp, blocksize);
+ if (tmp != *iblock) {
+ brelse(*bh);
+ *bh = NULL;
+ return 1;
+ }
+ if (!*bh)
+ return -1;
+ return 0;
+}
+
+
+static int sync_direct(struct inode *inode, int wait)
+{
+ int i;
+ int rc, err = 0;
+
+ for (i = 0; i < 8; i++) {
+ rc = sync_block (inode, inode->u.ext_i.i_data + i, wait);
+ if (rc > 0)
+ break;
+ if (rc)
+ err = rc;
+ }
+ return err;
+}
+
+static int sync_indirect(struct inode *inode, unsigned long *iblock, int wait)
+{
+ int i;
+ struct buffer_head * ind_bh;
+ int rc, err = 0;
+
+ rc = sync_iblock (inode, iblock, &ind_bh, wait);
+ if (rc || !ind_bh)
+ return rc;
+
+ for (i = 0; i < addr_per_block; i++) {
+ rc = sync_block (inode,
+ ((unsigned long *) ind_bh->b_data) + i,
+ wait);
+ if (rc > 0)
+ break;
+ if (rc)
+ err = rc;
+ }
+ brelse(ind_bh);
+ return err;
+}
+
+static int sync_dindirect(struct inode *inode, unsigned long *diblock,
+ int wait)
+{
+ int i;
+ struct buffer_head * dind_bh;
+ int rc, err = 0;
+
+ rc = sync_iblock (inode, diblock, &dind_bh, wait);
+ if (rc || !dind_bh)
+ return rc;
+
+ for (i = 0; i < addr_per_block; i++) {
+ rc = sync_indirect (inode,
+ ((unsigned long *) dind_bh->b_data) + i,
+ wait);
+ if (rc > 0)
+ break;
+ if (rc)
+ err = rc;
+ }
+ brelse(dind_bh);
+ return err;
+}
+
+int xiafs_sync_file(struct inode * inode, struct file * file)
+{
+ int wait, err = 0;
+
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+ S_ISLNK(inode->i_mode)))
+ return -EINVAL;
+ for (wait=0; wait<=1; wait++)
+ {
+ err |= sync_direct(inode, wait);
+ err |= sync_indirect(inode, &inode->u.xiafs_i.i_ind_zone, wait);
+ err |= sync_dindirect(inode, &inode->u.xiafs_i.i_dind_zone, wait);
+ }
+ err |= xiafs_sync_inode (inode);
+ return (err < 0) ? -EIO : 0;
+}
diff --git a/fs/xiafs/inode.c b/fs/xiafs/inode.c
new file mode 100644
index 000000000..171499a95
--- /dev/null
+++ b/fs/xiafs/inode.c
@@ -0,0 +1,502 @@
+/*
+ * linux/fs/xiafs/inode.c
+ *
+ * Copyright (C) Q. Frank Xia, 1993.
+ *
+ * Based on Linus' minix/inode.c
+ * Copyright (C) Linus Torvalds, 1991, 1992.
+ *
+ * This software may be redistributed per Linux Copyright.
+ */
+
+#include <linux/sched.h>
+#include <linux/xia_fs.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/locks.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+
+#include "xiafs_mac.h"
+
+static u_long random_nr;
+
+void xiafs_put_inode(struct inode *inode)
+{
+ if (inode->i_nlink)
+ return;
+ inode->i_size = 0;
+ xiafs_truncate(inode);
+ xiafs_free_inode(inode);
+}
+
+void xiafs_put_super(struct super_block *sb)
+{
+ int i;
+
+ lock_super(sb);
+ sb->s_dev = 0;
+ for(i = 0 ; i < _XIAFS_IMAP_SLOTS ; i++)
+ brelse(sb->u.xiafs_sb.s_imap_buf[i]);
+ for(i = 0 ; i < _XIAFS_ZMAP_SLOTS ; i++)
+ brelse(sb->u.xiafs_sb.s_zmap_buf[i]);
+ unlock_super(sb);
+}
+
+static struct super_operations xiafs_sops = {
+ xiafs_read_inode,
+ NULL,
+ xiafs_write_inode,
+ xiafs_put_inode,
+ xiafs_put_super,
+ NULL,
+ xiafs_statfs,
+ NULL
+};
+
+struct super_block *xiafs_read_super(struct super_block *s, void *data,
+ int silent)
+{
+ struct buffer_head *bh;
+ struct xiafs_super_block *sp;
+ int i, z, dev;
+
+ dev=s->s_dev;
+ lock_super(s);
+
+ set_blocksize(dev, BLOCK_SIZE);
+
+ if (!(bh = bread(dev, 0, BLOCK_SIZE))) {
+ s->s_dev=0;
+ unlock_super(s);
+ printk("XIA-FS: read super_block failed (%s %d)\n", WHERE_ERR);
+ return NULL;
+ }
+ sp = (struct xiafs_super_block *) bh->b_data;
+ s->s_magic = sp->s_magic;
+ if (s->s_magic != _XIAFS_SUPER_MAGIC) {
+ s->s_dev = 0;
+ unlock_super(s);
+ brelse(bh);
+ if (!silent)
+ printk("VFS: Can't find a xiafs filesystem on dev 0x%04x.\n",
+ dev);
+ return NULL;
+ }
+ s->s_blocksize = sp->s_zone_size;
+ s->s_blocksize_bits = 10 + sp->s_zone_shift;
+ if (s->s_blocksize != BLOCK_SIZE &&
+ (s->s_blocksize == 1024 || s->s_blocksize == 2048 ||
+ s->s_blocksize == 4096)) {
+ brelse(bh);
+ set_blocksize(dev, s->s_blocksize);
+ bh = bread (dev, 0, s->s_blocksize);
+ if(!bh) return NULL;
+ sp = (struct xiafs_super_block *) (((char *)bh->b_data) + BLOCK_SIZE) ;
+ };
+ s->u.xiafs_sb.s_nzones = sp->s_nzones;
+ s->u.xiafs_sb.s_ninodes = sp->s_ninodes;
+ s->u.xiafs_sb.s_ndatazones = sp->s_ndatazones;
+ s->u.xiafs_sb.s_imap_zones = sp->s_imap_zones;
+ s->u.xiafs_sb.s_zmap_zones = sp->s_zmap_zones;
+ s->u.xiafs_sb.s_firstdatazone = sp->s_firstdatazone;
+ s->u.xiafs_sb.s_zone_shift = sp->s_zone_shift;
+ s->u.xiafs_sb.s_max_size = sp->s_max_size;
+ brelse(bh);
+ for (i=0;i < _XIAFS_IMAP_SLOTS;i++) {
+ s->u.xiafs_sb.s_imap_buf[i] = NULL;
+ s->u.xiafs_sb.s_imap_iznr[i] = -1;
+ }
+ for (i=0;i < _XIAFS_ZMAP_SLOTS;i++) {
+ s->u.xiafs_sb.s_zmap_buf[i] = NULL;
+ s->u.xiafs_sb.s_zmap_zznr[i] = -1;
+ }
+ z=1;
+ if ( s->u.xiafs_sb.s_imap_zones > _XIAFS_IMAP_SLOTS )
+ s->u.xiafs_sb.s_imap_cached=1;
+ else {
+ s->u.xiafs_sb.s_imap_cached=0;
+ for (i=0 ; i < s->u.xiafs_sb.s_imap_zones ; i++) {
+ if (!(s->u.xiafs_sb.s_imap_buf[i]=bread(dev, z++, XIAFS_ZSIZE(s))))
+ goto xiafs_read_super_fail;
+ s->u.xiafs_sb.s_imap_iznr[i]=i;
+ }
+ }
+ if ( s->u.xiafs_sb.s_zmap_zones > _XIAFS_ZMAP_SLOTS )
+ s->u.xiafs_sb.s_zmap_cached=1;
+ else {
+ s->u.xiafs_sb.s_zmap_cached=0;
+ for (i=0 ; i < s->u.xiafs_sb.s_zmap_zones ; i++) {
+ if (!(s->u.xiafs_sb.s_zmap_buf[i]=bread(dev, z++, XIAFS_ZSIZE(s))))
+ goto xiafs_read_super_fail;
+ s->u.xiafs_sb.s_zmap_zznr[i]=i;
+ }
+ }
+ /* set up enough so that it can read an inode */
+ s->s_dev = dev;
+ s->s_op = &xiafs_sops;
+ s->s_mounted = iget(s, _XIAFS_ROOT_INO);
+ if (!s->s_mounted)
+ goto xiafs_read_super_fail;
+ unlock_super(s);
+ random_nr=CURRENT_TIME;
+ return s;
+
+xiafs_read_super_fail:
+ for(i=0; i < _XIAFS_IMAP_SLOTS; i++)
+ brelse(s->u.xiafs_sb.s_imap_buf[i]);
+ for(i=0; i < _XIAFS_ZMAP_SLOTS; i++)
+ brelse(s->u.xiafs_sb.s_zmap_buf[i]);
+ s->s_dev=0;
+ unlock_super(s);
+ printk("XIA-FS: read bitmaps failed (%s %d)\n", WHERE_ERR);
+ return NULL;
+}
+
+void xiafs_statfs(struct super_block *sb, struct statfs *buf)
+{
+ long tmp;
+
+ put_fs_long(_XIAFS_SUPER_MAGIC, &buf->f_type);
+ put_fs_long(XIAFS_ZSIZE(sb), &buf->f_bsize);
+ put_fs_long(sb->u.xiafs_sb.s_ndatazones, &buf->f_blocks);
+ tmp = xiafs_count_free_zones(sb);
+ put_fs_long(tmp, &buf->f_bfree);
+ put_fs_long(tmp, &buf->f_bavail);
+ put_fs_long(sb->u.xiafs_sb.s_ninodes, &buf->f_files);
+ put_fs_long(xiafs_count_free_inodes(sb), &buf->f_ffree);
+ put_fs_long(_XIAFS_NAME_LEN, &buf->f_namelen);
+ /* don't know what should be put in buf->f_fsid */
+}
+
+static int zone_bmap(struct buffer_head * bh, int nr)
+{
+ int tmp;
+
+ if (!bh)
+ return 0;
+ tmp = ((u_long *) bh->b_data)[nr];
+ brelse(bh);
+ return tmp;
+}
+
+int xiafs_bmap(struct inode * inode,int zone)
+{
+ int i;
+
+ if (zone < 0) {
+ printk("XIA-FS: block < 0 (%s %d)\n", WHERE_ERR);
+ return 0;
+ }
+ if (zone >= 8+(1+XIAFS_ADDRS_PER_Z(inode->i_sb))*XIAFS_ADDRS_PER_Z(inode->i_sb)) {
+ printk("XIA-FS: zone > big (%s %d)\n", WHERE_ERR);
+ return 0;
+ }
+ if (!IS_RDONLY (inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
+ if (zone < 8)
+ return inode->u.xiafs_i.i_zone[zone];
+ zone -= 8;
+ if (zone < XIAFS_ADDRS_PER_Z(inode->i_sb)) {
+ i = inode->u.xiafs_i.i_ind_zone;
+ if (i)
+ i = zone_bmap(bread(inode->i_dev, i, XIAFS_ZSIZE(inode->i_sb)), zone);
+ return i;
+ }
+ zone -= XIAFS_ADDRS_PER_Z(inode->i_sb);
+ i = inode->u.xiafs_i.i_dind_zone;
+ if (i)
+ i = zone_bmap(bread(inode->i_dev, i, XIAFS_ZSIZE(inode->i_sb)),
+ zone >> XIAFS_ADDRS_PER_Z_BITS(inode->i_sb));
+ if (i)
+ i= zone_bmap(bread(inode->i_dev,i, XIAFS_ZSIZE(inode->i_sb)),
+ zone & (XIAFS_ADDRS_PER_Z(inode->i_sb)-1));
+ return i;
+}
+
+static u_long get_prev_addr(struct inode * inode, int zone)
+{
+ u_long tmp;
+
+ if (zone > 0)
+ while (--zone >= 0) /* only files with holes suffer */
+ if ((tmp=xiafs_bmap(inode, zone)))
+ return tmp;
+ random_nr=(random_nr+23)%inode->i_sb->u.xiafs_sb.s_ndatazones;
+ return random_nr + inode->i_sb->u.xiafs_sb.s_firstdatazone;
+}
+
+static struct buffer_head *
+dt_getblk(struct inode * inode, u_long *lp, int create, u_long prev_addr)
+{
+ int tmp;
+ struct buffer_head * result;
+
+repeat:
+ if ((tmp=*lp)) {
+ result = getblk(inode->i_dev, tmp, XIAFS_ZSIZE(inode->i_sb));
+ if (tmp == *lp)
+ return result;
+ brelse(result);
+ goto repeat;
+ }
+ if (!create)
+ return NULL;
+ tmp = xiafs_new_zone(inode->i_sb, prev_addr);
+ if (!tmp)
+ return NULL;
+ result = getblk(inode->i_dev, tmp, XIAFS_ZSIZE(inode->i_sb));
+ if (*lp) {
+ xiafs_free_zone(inode->i_sb, tmp);
+ brelse(result);
+ goto repeat;
+ }
+ *lp = tmp;
+ inode->i_blocks+=2 << XIAFS_ZSHIFT(inode->i_sb);
+ return result;
+}
+
+static struct buffer_head *
+indt_getblk(struct inode * inode, struct buffer_head * bh,
+ int nr, int create, u_long prev_addr)
+{
+ int tmp;
+ u_long *lp;
+ struct buffer_head * result;
+
+ if (!bh)
+ return NULL;
+ if (!bh->b_uptodate) {
+ ll_rw_block(READ, 1, &bh);
+ wait_on_buffer(bh);
+ if (!bh->b_uptodate) {
+ brelse(bh);
+ return NULL;
+ }
+ }
+ lp = nr + (u_long *) bh->b_data;
+repeat:
+ if ((tmp=*lp)) {
+ result = getblk(bh->b_dev, tmp, XIAFS_ZSIZE(inode->i_sb));
+ if (tmp == *lp) {
+ brelse(bh);
+ return result;
+ }
+ brelse(result);
+ goto repeat;
+ }
+ if (!create) {
+ brelse(bh);
+ return NULL;
+ }
+ tmp = xiafs_new_zone(inode->i_sb, prev_addr);
+ if (!tmp) {
+ brelse(bh);
+ return NULL;
+ }
+ result = getblk(bh->b_dev, tmp, XIAFS_ZSIZE(inode->i_sb));
+ if (*lp) {
+ xiafs_free_zone(inode->i_sb, tmp);
+ brelse(result);
+ goto repeat;
+ }
+ *lp = tmp;
+ inode->i_blocks+=2 << XIAFS_ZSHIFT(inode->i_sb);
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ return result;
+}
+
+struct buffer_head * xiafs_getblk(struct inode * inode, int zone, int create)
+{
+ struct buffer_head * bh;
+ u_long prev_addr=0;
+
+ if (zone<0) {
+ printk("XIA-FS: zone < 0 (%s %d)\n", WHERE_ERR);
+ return NULL;
+ }
+ if (zone >= 8+(1+XIAFS_ADDRS_PER_Z(inode->i_sb))*XIAFS_ADDRS_PER_Z(inode->i_sb)) {
+ if (!create)
+ printk("XIA-FS: zone > big (%s %d)\n", WHERE_ERR);
+ return NULL;
+ }
+ if (create)
+ prev_addr=get_prev_addr(inode, zone);
+ if (zone < 8)
+ return dt_getblk(inode, zone+inode->u.xiafs_i.i_zone, create, prev_addr);
+ zone -= 8;
+ if (zone < XIAFS_ADDRS_PER_Z(inode->i_sb)) {
+ bh = dt_getblk(inode, &(inode->u.xiafs_i.i_ind_zone), create, prev_addr);
+ bh = indt_getblk(inode, bh, zone, create, prev_addr);
+ return bh;
+ }
+ zone -= XIAFS_ADDRS_PER_Z(inode->i_sb);
+ bh = dt_getblk(inode, &(inode->u.xiafs_i.i_dind_zone), create, prev_addr);
+ bh = indt_getblk(inode, bh, zone>>XIAFS_ADDRS_PER_Z_BITS(inode->i_sb),
+ create, prev_addr);
+ bh = indt_getblk(inode, bh, zone&(XIAFS_ADDRS_PER_Z(inode->i_sb)-1),
+ create, prev_addr);
+ return bh;
+}
+
+struct buffer_head * xiafs_bread(struct inode * inode, int zone, int create)
+{
+ struct buffer_head * bh;
+
+ bh = xiafs_getblk(inode, zone, create);
+ if (!bh || bh->b_uptodate)
+ return bh;
+ ll_rw_block(READ, 1, &bh);
+ wait_on_buffer(bh);
+ if (bh->b_uptodate)
+ return bh;
+ brelse(bh);
+ return NULL;
+}
+
+void xiafs_read_inode(struct inode * inode)
+{
+ struct buffer_head * bh;
+ struct xiafs_inode * raw_inode;
+ int zone;
+ ino_t ino;
+
+ ino = inode->i_ino;
+ inode->i_op = NULL;
+ inode->i_mode=0;
+ if (!ino || ino > inode->i_sb->u.xiafs_sb.s_ninodes) {
+ printk("XIA-FS: bad inode number (%s %d)\n", WHERE_ERR);
+ return;
+ }
+ zone = 1 + inode->i_sb->u.xiafs_sb.s_imap_zones +
+ inode->i_sb->u.xiafs_sb.s_zmap_zones +
+ (ino-1)/ XIAFS_INODES_PER_Z(inode->i_sb);
+ if (!(bh=bread(inode->i_dev, zone, XIAFS_ZSIZE(inode->i_sb)))) {
+ printk("XIA-FS: read i-node zone failed (%s %d)\n", WHERE_ERR);
+ return;
+ }
+ raw_inode = ((struct xiafs_inode *) bh->b_data) +
+ ((ino-1) & (XIAFS_INODES_PER_Z(inode->i_sb) - 1));
+ inode->i_mode = raw_inode->i_mode;
+ inode->i_uid = raw_inode->i_uid;
+ inode->i_gid = raw_inode->i_gid;
+ inode->i_nlink = raw_inode->i_nlinks;
+ inode->i_size = raw_inode->i_size;
+ inode->i_mtime = raw_inode->i_mtime;
+ inode->i_atime = raw_inode->i_atime;
+ inode->i_ctime = raw_inode->i_ctime;
+ inode->i_blksize = XIAFS_ZSIZE(inode->i_sb);
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
+ inode->i_blocks=0;
+ inode->i_rdev = raw_inode->i_zone[0];
+ } else {
+ XIAFS_GET_BLOCKS(raw_inode, inode->i_blocks);
+ for (zone = 0; zone < 8; zone++)
+ inode->u.xiafs_i.i_zone[zone] = raw_inode->i_zone[zone] & 0xffffff;
+ inode->u.xiafs_i.i_ind_zone = raw_inode->i_ind_zone & 0xffffff;
+ inode->u.xiafs_i.i_dind_zone = raw_inode->i_dind_zone & 0xffffff;
+ }
+ brelse(bh);
+ if (S_ISREG(inode->i_mode))
+ inode->i_op = &xiafs_file_inode_operations;
+ else if (S_ISDIR(inode->i_mode))
+ inode->i_op = &xiafs_dir_inode_operations;
+ else if (S_ISLNK(inode->i_mode))
+ inode->i_op = &xiafs_symlink_inode_operations;
+ else if (S_ISCHR(inode->i_mode))
+ inode->i_op = &chrdev_inode_operations;
+ else if (S_ISBLK(inode->i_mode))
+ inode->i_op = &blkdev_inode_operations;
+ else if (S_ISFIFO(inode->i_mode))
+ init_fifo(inode);
+}
+
+static struct buffer_head * xiafs_update_inode(struct inode * inode)
+{
+ struct buffer_head * bh;
+ struct xiafs_inode * raw_inode;
+ int zone;
+ ino_t ino;
+
+ if (IS_RDONLY (inode)) {
+ printk("XIA-FS: write_inode on a read-only filesystem (%s %d)\n", WHERE_ERR);
+ inode->i_dirt = 0;
+ return 0;
+ }
+
+ ino = inode->i_ino;
+ if (!ino || ino > inode->i_sb->u.xiafs_sb.s_ninodes) {
+ printk("XIA-FS: bad inode number (%s %d)\n", WHERE_ERR);
+ inode->i_dirt=0;
+ return 0;
+ }
+ zone = 1 + inode->i_sb->u.xiafs_sb.s_imap_zones +
+ inode->i_sb->u.xiafs_sb.s_zmap_zones +
+ (ino-1) / XIAFS_INODES_PER_Z(inode->i_sb);
+ if (!(bh=bread(inode->i_dev, zone, XIAFS_ZSIZE(inode->i_sb)))) {
+ printk("XIA-FS: read i-node zone failed (%s %d)\n", WHERE_ERR);
+ inode->i_dirt=0;
+ return 0;
+ }
+ raw_inode = ((struct xiafs_inode *)bh->b_data) +
+ ((ino-1) & (XIAFS_INODES_PER_Z(inode->i_sb) -1));
+ raw_inode->i_mode = inode->i_mode;
+ raw_inode->i_uid = inode->i_uid;
+ raw_inode->i_gid = inode->i_gid;
+ raw_inode->i_nlinks = inode->i_nlink;
+ raw_inode->i_size = inode->i_size;
+ raw_inode->i_atime = inode->i_atime;
+ raw_inode->i_ctime = inode->i_ctime;
+ raw_inode->i_mtime = inode->i_mtime;
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ raw_inode->i_zone[0] = inode->i_rdev;
+ else {
+ XIAFS_PUT_BLOCKS(raw_inode, inode->i_blocks);
+ for (zone = 0; zone < 8; zone++)
+ raw_inode->i_zone[zone] = (raw_inode->i_zone[zone] & 0xff000000)
+ | (inode->u.xiafs_i.i_zone[zone] & 0xffffff);
+ raw_inode->i_ind_zone = (raw_inode->i_ind_zone & 0xff000000)
+ | (inode->u.xiafs_i.i_ind_zone & 0xffffff);
+ raw_inode->i_dind_zone = (raw_inode->i_dind_zone & 0xff000000)
+ | (inode->u.xiafs_i.i_dind_zone & 0xffffff);
+ }
+ inode->i_dirt=0;
+ mark_buffer_dirty(bh, 1);
+ return bh;
+}
+
+
+void xiafs_write_inode(struct inode * inode)
+{
+ struct buffer_head * bh;
+ bh = xiafs_update_inode(inode);
+ brelse (bh);
+}
+
+int xiafs_sync_inode (struct inode *inode)
+{
+ int err = 0;
+ struct buffer_head *bh;
+
+ bh = xiafs_update_inode(inode);
+ if (bh && bh->b_dirt)
+ {
+ ll_rw_block(WRITE, 1, &bh);
+ wait_on_buffer(bh);
+ if (bh->b_req && !bh->b_uptodate)
+ {
+ printk ("IO error syncing xiafs inode [%04X:%lu]\n",
+ inode->i_dev, inode->i_ino);
+ err = -1;
+ }
+ }
+ else if (!bh)
+ err = -1;
+ brelse (bh);
+ return err;
+}
diff --git a/fs/xiafs/namei.c b/fs/xiafs/namei.c
new file mode 100644
index 000000000..0532b1754
--- /dev/null
+++ b/fs/xiafs/namei.c
@@ -0,0 +1,848 @@
+/*
+ * Linux/fs/xiafs/namei.c
+ *
+ * Copyright (C) Q. Frank Xia, 1993.
+ *
+ * Based on Linus' minix/namei.c
+ * Copyright (C) Linus Torvalds, 1991, 1992.
+ *
+ * This software may be redistributed per Linux Copyright.
+ */
+
+#include <linux/sched.h>
+#include <linux/xia_fs.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/errno.h>
+#include <asm/segment.h>
+
+#include "xiafs_mac.h"
+
+#define RNDUP4(x) ((3+(u_long)(x)) & ~3)
+/*
+ * ok, we cannot use strncmp, as the name is not in our data space.
+ * Thus we'll have to use xiafs_match. No big problem. Match also makes
+ * some sanity tests.
+ *
+ * NOTE! unlike strncmp, xiafs_match returns 1 for success, 0 for failure.
+ */
+static int xiafs_match(int len, const char * name, struct xiafs_direct * dep)
+{
+ int i;
+
+ if (!dep || !dep->d_ino || len > _XIAFS_NAME_LEN)
+ return 0;
+ /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
+ if (!len && (dep->d_name[0]=='.') && (dep->d_name[1]=='\0'))
+ return 1;
+ if (len != dep->d_name_len)
+ return 0;
+ for (i=0; i < len; i++)
+ if (*name++ != dep->d_name[i])
+ return 0;
+ return 1;
+}
+
+/*
+ * xiafs_find_entry()
+ *
+ * finds an entry in the specified directory with the wanted name. It
+ * returns the cache buffer in which the entry was found, and the entry
+ * itself (as a parameter - res_dir). It does NOT read the inode of the
+ * entry - you'll have to do that yourself if you want to.
+ */
+static struct buffer_head *
+xiafs_find_entry(struct inode * inode, const char * name, int namelen,
+ struct xiafs_direct ** res_dir, struct xiafs_direct ** res_pre)
+{
+ int i, zones, pos;
+ struct buffer_head * bh;
+ struct xiafs_direct * dep, * dep_pre;
+
+ *res_dir = NULL;
+ if (!inode)
+ return NULL;
+ if (namelen > _XIAFS_NAME_LEN)
+ return NULL;
+
+ if (inode->i_size & (XIAFS_ZSIZE(inode->i_sb) - 1)) {
+ printk("XIA-FS: bad dir size (%s %d)\n", WHERE_ERR);
+ return NULL;
+ }
+ zones=inode->i_size >> XIAFS_ZSIZE_BITS(inode->i_sb);
+ for (i=0; i < zones; i++ ) {
+ bh = xiafs_bread(inode, i, 0);
+ if (!bh)
+ continue;
+ dep_pre=dep=(struct xiafs_direct *)bh->b_data;
+ if (!i && (dep->d_rec_len != 12 || !dep->d_ino ||
+ dep->d_name_len != 1 || strcmp(dep->d_name, "."))) {
+ printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
+ brelse(bh);
+ return NULL;
+ }
+ pos = 0;
+ while ( pos < XIAFS_ZSIZE(inode->i_sb) ) {
+ if (dep->d_ino > inode->i_sb->u.xiafs_sb.s_ninodes ||
+ dep->d_rec_len < 12 ||
+ dep->d_rec_len+(char *)dep > bh->b_data+XIAFS_ZSIZE(inode->i_sb) ||
+ dep->d_name_len + 8 > dep->d_rec_len || dep->d_name_len <= 0 ||
+ dep->d_name[dep->d_name_len] ) {
+ brelse(bh);
+ return NULL;
+ }
+ if (xiafs_match(namelen, name, dep)) {
+ *res_dir=dep;
+ if (res_pre)
+ *res_pre=dep_pre;
+ return bh;
+ }
+ pos += dep->d_rec_len;
+ dep_pre=dep;
+ dep=(struct xiafs_direct *)(bh->b_data + pos);
+ }
+ brelse(bh);
+ if (pos > XIAFS_ZSIZE(inode->i_sb)) {
+ printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+int xiafs_lookup(struct inode * dir, const char * name, int len,
+ struct inode ** result)
+{
+ int ino;
+ struct xiafs_direct * dep;
+ struct buffer_head * bh;
+
+ *result = NULL;
+ if (!dir)
+ return -ENOENT;
+ if (!S_ISDIR(dir->i_mode)) {
+ iput(dir);
+ return -ENOENT;
+ }
+ if (!(bh = xiafs_find_entry(dir, name, len, &dep, NULL))) {
+ iput(dir);
+ return -ENOENT;
+ }
+ ino = dep->d_ino;
+ brelse(bh);
+ if (!(*result = iget(dir->i_sb, ino))) {
+ iput(dir);
+ return -EACCES;
+ }
+ iput(dir);
+ return 0;
+}
+
+/*
+ * xiafs_add_entry()
+ *
+ * adds a file entry to the specified directory, using the same
+ * semantics as xiafs_find_entry(). It returns NULL if it failed.
+ *
+ * NOTE!! The inode part of 'de' is left at 0 - which means you
+ * may not sleep between calling this and putting something into
+ * the entry, as someone else might have used it while you slept.
+ */
+static struct buffer_head * xiafs_add_entry(struct inode * dir,
+ const char * name, int namelen, struct xiafs_direct ** res_dir,
+ struct xiafs_direct ** res_pre)
+{
+ int i, pos, offset;
+ struct buffer_head * bh;
+ struct xiafs_direct * de, * de_pre;
+
+ *res_dir = NULL;
+ if (!dir || !namelen || namelen > _XIAFS_NAME_LEN)
+ return NULL;
+
+ if (dir->i_size & (XIAFS_ZSIZE(dir->i_sb) - 1)) {
+ printk("XIA-FS: bad dir size (%s %d)\n", WHERE_ERR);
+ return NULL;
+ }
+ pos=0;
+ for ( ; ; ) {
+ bh = xiafs_bread(dir, pos >> XIAFS_ZSIZE_BITS(dir->i_sb), pos ? 1:0);
+ if (!bh)
+ return NULL;
+ de_pre=de=(struct xiafs_direct *)bh->b_data;
+ if (!pos) {
+ if (de->d_rec_len != 12 || !de->d_ino || de->d_name_len != 1 ||
+ strcmp(de->d_name, ".")) {
+ printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
+ brelse(bh);
+ return NULL;
+ }
+ offset = 12;
+ de_pre=de=(struct xiafs_direct *)(bh->b_data+12);
+ } else
+ offset = 0;
+ while (offset < XIAFS_ZSIZE(dir->i_sb)) {
+ if (pos >= dir->i_size) {
+ de->d_ino=0;
+ de->d_name_len=0;
+ de->d_name[0]=0;
+ de->d_rec_len=XIAFS_ZSIZE(dir->i_sb);
+ dir->i_size += XIAFS_ZSIZE(dir->i_sb);
+ dir->i_dirt = 1;
+ } else {
+ if (de->d_ino > dir->i_sb->u.xiafs_sb.s_ninodes ||
+ de->d_rec_len < 12 ||
+ (char *)de+de->d_rec_len > bh->b_data+XIAFS_ZSIZE(dir->i_sb) ||
+ de->d_name_len + 8 > de->d_rec_len ||
+ de->d_name[de->d_name_len]) {
+ printk("XIA-FS: bad directory entry (%s %d)\n", WHERE_ERR);
+ brelse(bh);
+ return NULL;
+ }
+ if (de->d_ino &&
+ RNDUP4(de->d_name_len)+RNDUP4(namelen)+16<=de->d_rec_len) {
+ i=RNDUP4(de->d_name_len)+8;
+ de_pre=de;
+ de=(struct xiafs_direct *)(i+(u_char *)de_pre);
+ de->d_ino=0;
+ de->d_rec_len=de_pre->d_rec_len-i;
+ de_pre->d_rec_len=i;
+ }
+ }
+ if (!de->d_ino && RNDUP4(namelen)+8 <= de->d_rec_len) {
+ /*
+ * XXX all times should be set by caller upon successful
+ * completion.
+ */
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_dirt = 1;
+ memcpy(de->d_name, name, namelen);
+ de->d_name[namelen]=0;
+ de->d_name_len=namelen;
+ mark_buffer_dirty(bh, 1);
+ *res_dir = de;
+ if (res_pre)
+ *res_pre = de_pre;
+ return bh;
+ }
+ offset+=de->d_rec_len;
+ de_pre=de;
+ de=(struct xiafs_direct *)(bh->b_data+offset);
+ }
+ brelse(bh);
+ if (offset > XIAFS_ZSIZE(dir->i_sb)) {
+ printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
+ return NULL;
+ }
+ pos+=XIAFS_ZSIZE(dir->i_sb);
+ }
+ return NULL;
+}
+
+int xiafs_create(struct inode * dir, const char * name, int len, int mode,
+ struct inode ** result)
+{
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct xiafs_direct * de;
+
+ *result = NULL;
+ if (!dir)
+ return -ENOENT;
+ inode = xiafs_new_inode(dir);
+ if (!inode) {
+ iput(dir);
+ return -ENOSPC;
+ }
+ inode->i_op = &xiafs_file_inode_operations;
+ inode->i_mode = mode;
+ inode->i_dirt = 1;
+ bh = xiafs_add_entry(dir, name, len, &de, NULL);
+ if (!bh) {
+ inode->i_nlink--;
+ inode->i_dirt = 1;
+ iput(inode);
+ iput(dir);
+ return -ENOSPC;
+ }
+ de->d_ino = inode->i_ino;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ iput(dir);
+ *result = inode;
+ return 0;
+}
+
+int xiafs_mknod(struct inode *dir, const char *name, int len, int mode, int rdev)
+{
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct xiafs_direct * de;
+
+ if (!dir)
+ return -ENOENT;
+ bh = xiafs_find_entry(dir,name,len,&de, NULL);
+ if (bh) {
+ brelse(bh);
+ iput(dir);
+ return -EEXIST;
+ }
+ inode = xiafs_new_inode(dir);
+ if (!inode) {
+ iput(dir);
+ return -ENOSPC;
+ }
+ inode->i_uid = current->fsuid;
+ inode->i_mode = mode;
+ inode->i_op = NULL;
+ if (S_ISREG(inode->i_mode))
+ inode->i_op = &xiafs_file_inode_operations;
+ else if (S_ISDIR(inode->i_mode)) {
+ inode->i_op = &xiafs_dir_inode_operations;
+ if (dir->i_mode & S_ISGID)
+ inode->i_mode |= S_ISGID;
+ }
+ else if (S_ISLNK(inode->i_mode))
+ inode->i_op = &xiafs_symlink_inode_operations;
+ else if (S_ISCHR(inode->i_mode))
+ inode->i_op = &chrdev_inode_operations;
+ else if (S_ISBLK(inode->i_mode))
+ inode->i_op = &blkdev_inode_operations;
+ else if (S_ISFIFO(inode->i_mode))
+ init_fifo(inode);
+ if (S_ISBLK(mode) || S_ISCHR(mode))
+ inode->i_rdev = rdev;
+ inode->i_atime = inode->i_ctime = inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ bh = xiafs_add_entry(dir, name, len, &de, NULL);
+ if (!bh) {
+ inode->i_nlink--;
+ inode->i_dirt = 1;
+ iput(inode);
+ iput(dir);
+ return -ENOSPC;
+ }
+ de->d_ino = inode->i_ino;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ iput(dir);
+ iput(inode);
+ return 0;
+}
+
+int xiafs_mkdir(struct inode * dir, const char * name, int len, int mode)
+{
+ struct inode * inode;
+ struct buffer_head * bh, *dir_block;
+ struct xiafs_direct * de;
+
+ bh = xiafs_find_entry(dir,name,len,&de, NULL);
+ if (bh) {
+ brelse(bh);
+ iput(dir);
+ return -EEXIST;
+ }
+ if (dir->i_nlink > 64000) {
+ iput(dir);
+ return -EMLINK;
+ }
+ inode = xiafs_new_inode(dir);
+ if (!inode) {
+ iput(dir);
+ return -ENOSPC;
+ }
+ inode->i_op = &xiafs_dir_inode_operations;
+ inode->i_size = XIAFS_ZSIZE(dir->i_sb);
+ inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ dir_block = xiafs_bread(inode,0,1);
+ if (!dir_block) {
+ iput(dir);
+ inode->i_nlink--;
+ inode->i_dirt = 1;
+ iput(inode);
+ return -ENOSPC;
+ }
+ de = (struct xiafs_direct *) dir_block->b_data;
+ de->d_ino=inode->i_ino;
+ strcpy(de->d_name,".");
+ de->d_name_len=1;
+ de->d_rec_len=12;
+ de =(struct xiafs_direct *)(12 + dir_block->b_data);
+ de->d_ino = dir->i_ino;
+ strcpy(de->d_name,"..");
+ de->d_name_len=2;
+ de->d_rec_len=XIAFS_ZSIZE(dir->i_sb)-12;
+ inode->i_nlink = 2;
+ mark_buffer_dirty(dir_block, 1);
+ brelse(dir_block);
+ inode->i_mode = S_IFDIR | (mode & S_IRWXUGO & ~current->fs->umask);
+ if (dir->i_mode & S_ISGID)
+ inode->i_mode |= S_ISGID;
+ inode->i_dirt = 1;
+ bh = xiafs_add_entry(dir, name, len, &de, NULL);
+ if (!bh) {
+ iput(dir);
+ inode->i_nlink=0;
+ iput(inode);
+ return -ENOSPC;
+ }
+ de->d_ino = inode->i_ino;
+ mark_buffer_dirty(bh, 1);
+ dir->i_nlink++;
+ dir->i_dirt = 1;
+ iput(dir);
+ iput(inode);
+ brelse(bh);
+ return 0;
+}
+
+/*
+ * routine to check that the specified directory is empty (for rmdir)
+ */
+static int empty_dir(struct inode * inode)
+{
+ int i, zones, offset;
+ struct buffer_head * bh;
+ struct xiafs_direct * de;
+
+ if (inode->i_size & (XIAFS_ZSIZE(inode->i_sb)-1) ) {
+ printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
+ return 1;
+ }
+
+ zones=inode->i_size >> XIAFS_ZSIZE_BITS(inode->i_sb);
+ for (i=0; i < zones; i++) {
+ bh = xiafs_bread(inode, i, 0);
+ if (!i) {
+ if (!bh) {
+ printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
+ return 1;
+ }
+ de=(struct xiafs_direct *)bh->b_data;
+ if (de->d_ino != inode->i_ino || strcmp(".", de->d_name) ||
+ de->d_rec_len != 12 ) {
+ printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
+ brelse(bh);
+ return 1;
+ }
+ de=(struct xiafs_direct *)(12 + bh->b_data);
+ if (!de->d_ino || strcmp("..", de->d_name)) {
+ printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
+ brelse(bh);
+ return 1;
+ }
+ offset=de->d_rec_len+12;
+ }
+ else
+ offset = 0;
+ if (!bh)
+ continue;
+ while (offset < XIAFS_ZSIZE(inode->i_sb)) {
+ de=(struct xiafs_direct *)(bh->b_data+offset);
+ if (de->d_ino > inode->i_sb->u.xiafs_sb.s_ninodes ||
+ de->d_rec_len < 12 ||
+ (char *)de+de->d_rec_len > bh->b_data+XIAFS_ZSIZE(inode->i_sb) ||
+ de->d_name_len + 8 > de->d_rec_len ||
+ de->d_name[de->d_name_len]) {
+ printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
+ brelse(bh);
+ return 1;
+ }
+ if (de->d_ino) {
+ brelse(bh);
+ return 0;
+ }
+ offset+=de->d_rec_len;
+ }
+ brelse(bh);
+ }
+ return 1;
+}
+
+static void xiafs_rm_entry(struct xiafs_direct *de, struct xiafs_direct * de_pre)
+{
+ if (de==de_pre) {
+ de->d_ino=0;
+ return;
+ }
+ while (de_pre->d_rec_len+(u_char *)de_pre < (u_char *)de) {
+ if (de_pre->d_rec_len < 12) {
+ printk("XIA-FS: bad directory entry (%s %d)\n", WHERE_ERR);
+ return;
+ }
+ de_pre=(struct xiafs_direct *)(de_pre->d_rec_len+(u_char *)de_pre);
+ }
+ if (de_pre->d_rec_len+(u_char *)de_pre > (u_char *)de) {
+ printk("XIA-FS: bad directory entry (%s %d)\n", WHERE_ERR);
+ return;
+ }
+ de_pre->d_rec_len+=de->d_rec_len;
+}
+
+int xiafs_rmdir(struct inode * dir, const char * name, int len)
+{
+ int retval;
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct xiafs_direct * de, * de_pre;
+
+ inode = NULL;
+ bh = xiafs_find_entry(dir, name, len, &de, &de_pre);
+ retval = -ENOENT;
+ if (!bh)
+ goto end_rmdir;
+ retval = -EPERM;
+ if (!(inode = iget(dir->i_sb, de->d_ino)))
+ goto end_rmdir;
+ if ((dir->i_mode & S_ISVTX) && !fsuser() &&
+ current->fsuid != inode->i_uid &&
+ current->fsuid != dir->i_uid)
+ goto end_rmdir;
+ if (inode->i_dev != dir->i_dev)
+ goto end_rmdir;
+ if (inode == dir) /* we may not delete ".", but "../dir" is ok */
+ goto end_rmdir;
+ if (!S_ISDIR(inode->i_mode)) {
+ retval = -ENOTDIR;
+ goto end_rmdir;
+ }
+ if (!empty_dir(inode)) {
+ retval = -ENOTEMPTY;
+ goto end_rmdir;
+ }
+ if (inode->i_count > 1) {
+ retval = -EBUSY;
+ goto end_rmdir;
+ }
+ if (inode->i_nlink != 2)
+ printk("XIA-FS: empty directory has nlink!=2 (%s %d)\n", WHERE_ERR);
+ xiafs_rm_entry(de, de_pre);
+ mark_buffer_dirty(bh, 1);
+ inode->i_nlink=0;
+ inode->i_dirt=1;
+ dir->i_nlink--;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_dirt=1;
+ retval = 0;
+end_rmdir:
+ iput(dir);
+ iput(inode);
+ brelse(bh);
+ return retval;
+}
+
+int xiafs_unlink(struct inode * dir, const char * name, int len)
+{
+ int retval;
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct xiafs_direct * de, * de_pre;
+
+repeat:
+ retval = -ENOENT;
+ inode = NULL;
+ bh = xiafs_find_entry(dir, name, len, &de, &de_pre);
+ if (!bh)
+ goto end_unlink;
+ if (!(inode = iget(dir->i_sb, de->d_ino)))
+ goto end_unlink;
+ retval = -EPERM;
+ if (S_ISDIR(inode->i_mode))
+ goto end_unlink;
+ if (de->d_ino != inode->i_ino) {
+ iput(inode);
+ brelse(bh);
+ current->counter = 0;
+ schedule();
+ goto repeat;
+ }
+ if ((dir->i_mode & S_ISVTX) && !fsuser() &&
+ current->fsuid != inode->i_uid &&
+ current->fsuid != dir->i_uid)
+ goto end_unlink;
+ if (!inode->i_nlink) {
+ printk("XIA-FS: Deleting nonexistent file (%s %d)\n", WHERE_ERR);
+ inode->i_nlink=1;
+ }
+ xiafs_rm_entry(de, de_pre);
+ mark_buffer_dirty(bh, 1);
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_dirt = 1;
+ inode->i_nlink--;
+ inode->i_dirt = 1;
+ retval = 0;
+end_unlink:
+ brelse(bh);
+ iput(inode);
+ iput(dir);
+ return retval;
+}
+
+int xiafs_symlink(struct inode * dir, const char * name,
+ int len, const char * symname)
+{
+ struct xiafs_direct * de;
+ struct inode * inode = NULL;
+ struct buffer_head * bh = NULL, * name_block = NULL;
+ int i;
+ char c;
+
+ bh = xiafs_find_entry(dir,name,len, &de, NULL);
+ if (bh) {
+ brelse(bh);
+ iput(dir);
+ return -EEXIST;
+ }
+ if (!(inode = xiafs_new_inode(dir))) {
+ iput(dir);
+ return -ENOSPC;
+ }
+ inode->i_mode = S_IFLNK | S_IRWXUGO;
+ inode->i_op = &xiafs_symlink_inode_operations;
+ name_block = xiafs_bread(inode,0,1);
+ if (!name_block) {
+ iput(dir);
+ inode->i_nlink--;
+ inode->i_dirt = 1;
+ iput(inode);
+ return -ENOSPC;
+ }
+ for (i = 0; i < BLOCK_SIZE-1 && (c=*symname++); i++)
+ name_block->b_data[i] = c;
+ name_block->b_data[i] = 0;
+ mark_buffer_dirty(name_block, 1);
+ brelse(name_block);
+ inode->i_size = i;
+ inode->i_dirt = 1;
+ bh = xiafs_add_entry(dir, name, len, &de, NULL);
+ if (!bh) {
+ inode->i_nlink--;
+ inode->i_dirt = 1;
+ iput(inode);
+ iput(dir);
+ return -ENOSPC;
+ }
+ de->d_ino = inode->i_ino;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ iput(dir);
+ iput(inode);
+ return 0;
+}
+
+int xiafs_link(struct inode * oldinode, struct inode * dir,
+ const char * name, int len)
+{
+ struct xiafs_direct * de;
+ struct buffer_head * bh;
+
+ if (S_ISDIR(oldinode->i_mode)) {
+ iput(oldinode);
+ iput(dir);
+ return -EPERM;
+ }
+ if (oldinode->i_nlink > 64000) {
+ iput(oldinode);
+ iput(dir);
+ return -EMLINK;
+ }
+ bh = xiafs_find_entry(dir, name, len, &de, NULL);
+ if (bh) {
+ brelse(bh);
+ iput(dir);
+ iput(oldinode);
+ return -EEXIST;
+ }
+ bh = xiafs_add_entry(dir, name, len, &de, NULL);
+ if (!bh) {
+ iput(dir);
+ iput(oldinode);
+ return -ENOSPC;
+ }
+ de->d_ino = oldinode->i_ino;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ iput(dir);
+ oldinode->i_nlink++;
+ oldinode->i_ctime = CURRENT_TIME;
+ oldinode->i_dirt = 1;
+ iput(oldinode);
+ return 0;
+}
+
+static int subdir(struct inode * new_inode, struct inode * old_inode)
+{
+ int ino;
+ int result;
+
+ new_inode->i_count++;
+ result = 0;
+ for (;;) {
+ if (new_inode == old_inode) {
+ result = 1;
+ break;
+ }
+ if (new_inode->i_dev != old_inode->i_dev)
+ break;
+ ino = new_inode->i_ino;
+ if (xiafs_lookup(new_inode,"..",2,&new_inode))
+ break;
+ if (new_inode->i_ino == ino)
+ break;
+ }
+ iput(new_inode);
+ return result;
+}
+
+#define PARENT_INO(buffer) \
+ (((struct xiafs_direct *) ((u_char *)(buffer) + 12))->d_ino)
+
+/*
+ * rename uses retry to avoid race-conditions: at least they should be minimal.
+ * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
+ * checks fail, it tries to restart itself again. Very practical - no changes
+ * are done until we know everything works ok.. and then all the changes can be
+ * done in one fell swoop when we have claimed all the buffers needed.
+ *
+ * Anybody can rename anything with this: the permission checks are left to the
+ * higher-level routines.
+ */
+static int do_xiafs_rename(struct inode * old_dir, const char * old_name,
+ int old_len, struct inode * new_dir,
+ const char * new_name, int new_len)
+{
+ struct inode * old_inode, * new_inode;
+ struct buffer_head * old_bh, * new_bh, * dir_bh;
+ struct xiafs_direct * old_de, * old_de_pre, * new_de, * new_de_pre;
+ int retval;
+
+try_again:
+ old_inode = new_inode = NULL;
+ old_bh = new_bh = dir_bh = NULL;
+ old_bh = xiafs_find_entry(old_dir, old_name, old_len, &old_de, &old_de_pre);
+ retval = -ENOENT;
+ if (!old_bh)
+ goto end_rename;
+ old_inode = __iget(old_dir->i_sb, old_de->d_ino, 0); /* don't cross mnt-points */
+ if (!old_inode)
+ goto end_rename;
+ retval = -EPERM;
+ if ((old_dir->i_mode & S_ISVTX) &&
+ current->fsuid != old_inode->i_uid &&
+ current->fsuid != old_dir->i_uid && !fsuser())
+ goto end_rename;
+ new_bh = xiafs_find_entry(new_dir, new_name, new_len, &new_de, NULL);
+ if (new_bh) {
+ new_inode = __iget(new_dir->i_sb, new_de->d_ino, 0);
+ if (!new_inode) {
+ brelse(new_bh);
+ new_bh = NULL;
+ }
+ }
+ if (new_inode == old_inode) {
+ retval = 0;
+ goto end_rename;
+ }
+ if (new_inode && S_ISDIR(new_inode->i_mode)) {
+ retval = -EEXIST;
+ goto end_rename;
+ }
+ retval = -EPERM;
+ if (new_inode && (new_dir->i_mode & S_ISVTX) &&
+ current->fsuid != new_inode->i_uid &&
+ current->fsuid != new_dir->i_uid && !fsuser())
+ goto end_rename;
+ if (S_ISDIR(old_inode->i_mode)) {
+ retval = -EEXIST;
+ if (new_bh)
+ goto end_rename;
+ retval = -EACCES;
+ if (!permission(old_inode, MAY_WRITE))
+ goto end_rename;
+ retval = -EINVAL;
+ if (subdir(new_dir, old_inode))
+ goto end_rename;
+ retval = -EIO;
+ dir_bh = xiafs_bread(old_inode,0,0);
+ if (!dir_bh)
+ goto end_rename;
+ if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
+ goto end_rename;
+ retval = -EMLINK;
+ if (new_dir->i_nlink > 64000)
+ goto end_rename;
+ }
+ if (!new_bh)
+ new_bh = xiafs_add_entry(new_dir, new_name, new_len, &new_de, &new_de_pre);
+ retval = -ENOSPC;
+ if (!new_bh)
+ goto end_rename;
+ /* sanity checking */
+ if ( (new_inode && (new_de->d_ino != new_inode->i_ino))
+ || (new_de->d_ino && !new_inode)
+ || (old_de->d_ino != old_inode->i_ino)) {
+ xiafs_rm_entry(new_de, new_de_pre);
+ brelse(old_bh);
+ brelse(new_bh);
+ brelse(dir_bh);
+ iput(old_inode);
+ iput(new_inode);
+ current->counter=0;
+ schedule();
+ goto try_again;
+ }
+ xiafs_rm_entry(old_de, old_de_pre);
+ new_de->d_ino = old_inode->i_ino;
+ if (new_inode) {
+ new_inode->i_nlink--;
+ new_inode->i_dirt = 1;
+ }
+ mark_buffer_dirty(old_bh, 1);
+ mark_buffer_dirty(new_bh, 1);
+ if (dir_bh) {
+ PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
+ mark_buffer_dirty(dir_bh, 1);
+ old_dir->i_nlink--;
+ new_dir->i_nlink++;
+ old_dir->i_dirt = 1;
+ new_dir->i_dirt = 1;
+ }
+ retval = 0;
+end_rename:
+ brelse(dir_bh);
+ brelse(old_bh);
+ brelse(new_bh);
+ iput(old_inode);
+ iput(new_inode);
+ iput(old_dir);
+ iput(new_dir);
+ return retval;
+}
+
+/*
+ * Ok, rename also locks out other renames, as they can change the parent of
+ * a directory, and we don't want any races. Other races are checked for by
+ * "do_rename()", which restarts if there are inconsistencies.
+ *
+ * Note that there is no race between different filesystems: it's only within
+ * the same device that races occur: many renames can happen at once, as long
+ * as they are on different partitions.
+ */
+int xiafs_rename(struct inode * old_dir, const char * old_name, int old_len,
+ struct inode * new_dir, const char * new_name, int new_len)
+{
+ static struct wait_queue * wait = NULL;
+ static int lock = 0;
+ int result;
+
+ while (lock)
+ sleep_on(&wait);
+ lock = 1;
+ result = do_xiafs_rename(old_dir, old_name, old_len,
+ new_dir, new_name, new_len);
+ lock = 0;
+ wake_up(&wait);
+ return result;
+}
diff --git a/fs/xiafs/symlink.c b/fs/xiafs/symlink.c
new file mode 100644
index 000000000..757ad5796
--- /dev/null
+++ b/fs/xiafs/symlink.c
@@ -0,0 +1,118 @@
+/*
+ * linux/fs/xiafs/symlink.c
+ *
+ * Copyright (C) Q. Frank Xia, 1993.
+ *
+ * Based on Linus' minix/symlink.c
+ * Copyright (C) Linus Torvalds, 1991, 1992.
+ *
+ * This software may be redistributed per Linux Copyright.
+ */
+
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/xia_fs.h>
+#include <linux/stat.h>
+
+static int
+xiafs_readlink(struct inode *, char *, int);
+
+static int
+xiafs_follow_link(struct inode *, struct inode *, int, int, struct inode **);
+
+/*
+ * symlinks can't do much...
+ */
+struct inode_operations xiafs_symlink_inode_operations = {
+ NULL, /* no file-operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ xiafs_readlink, /* readlink */
+ xiafs_follow_link, /* follow_link */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
+};
+
+static int xiafs_readlink(struct inode * inode, char * buffer, int buflen)
+{
+ struct buffer_head * bh;
+ int i;
+ char c;
+
+ if (!S_ISLNK(inode->i_mode)) {
+ iput(inode);
+ return -EINVAL;
+ }
+ if (buflen > BLOCK_SIZE)
+ buflen = BLOCK_SIZE;
+ bh = xiafs_bread(inode, 0, 0);
+ if (!IS_RDONLY (inode)) {
+ inode->i_atime=CURRENT_TIME;
+ inode->i_dirt=1;
+ }
+ iput(inode);
+ if (!bh)
+ return 0;
+ for (i=0; i < buflen && (c=bh->b_data[i]); i++)
+ put_fs_byte(c, buffer++);
+ if (i < buflen-1)
+ put_fs_byte((char)0, buffer);
+ brelse(bh);
+ return i;
+}
+
+static int xiafs_follow_link(struct inode * dir, struct inode * inode,
+ int flag, int mode, struct inode ** res_inode)
+{
+ int error;
+ struct buffer_head * bh;
+
+ *res_inode = NULL;
+ if (!dir) {
+ dir = current->fs->root;
+ dir->i_count++;
+ }
+ if (!inode) {
+ iput(dir);
+ return -ENOENT;
+ }
+ if (!S_ISLNK(inode->i_mode)) {
+ iput(dir);
+ *res_inode = inode;
+ return 0;
+ }
+ if (!IS_RDONLY (inode)) {
+ inode->i_atime=CURRENT_TIME;
+ inode->i_dirt=1;
+ }
+ if (current->link_count > 5) {
+ iput(inode);
+ iput(dir);
+ return -ELOOP;
+ }
+ if (!(bh = xiafs_bread(inode, 0, 0))) {
+ iput(inode);
+ iput(dir);
+ return -EIO;
+ }
+ iput(inode);
+ current->link_count++;
+ error = open_namei(bh->b_data,flag,mode,res_inode,dir);
+ current->link_count--;
+ brelse(bh);
+ return error;
+}
+
+
+
diff --git a/fs/xiafs/truncate.c b/fs/xiafs/truncate.c
new file mode 100644
index 000000000..bdb9d39be
--- /dev/null
+++ b/fs/xiafs/truncate.c
@@ -0,0 +1,197 @@
+/*
+ * linux/fs/xiafs/truncate.c
+ *
+ * Copyright (C) Q. Frank Xia, 1993.
+ *
+ * Based on Linus' minix/truncate.c
+ * Copyright (C) Linus Torvalds, 1991, 1992.
+ *
+ * This software may be redistributed per Linux Copyright.
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/xia_fs.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+
+#include "xiafs_mac.h"
+
+/*
+ * Linus' comment:
+ *
+ * Truncate has the most races in the whole filesystem: coding it is
+ * a pain in the a**. Especially as I don't do any locking...
+ *
+ * The code may look a bit weird, but that's just because I've tried to
+ * handle things like file-size changes in a somewhat graceful manner.
+ * Anyway, truncating a file at the same time somebody else writes to it
+ * is likely to result in pretty weird behaviour...
+ *
+ * The new code handles normal truncates (size = 0) as well as the more
+ * general case (size = XXX). I hope.
+ */
+
+#define DT_ZONE ((inode->i_size + XIAFS_ZSIZE(inode->i_sb) - 1) \
+ >> XIAFS_ZSIZE_BITS(inode->i_sb) )
+
+static int trunc_direct(struct inode * inode)
+{
+ u_long * lp;
+ struct buffer_head * bh;
+ int i, tmp;
+ int retry = 0;
+
+repeat:
+ for (i = DT_ZONE ; i < 8 ; i++) {
+ if (i < DT_ZONE)
+ goto repeat;
+ lp=i + inode->u.xiafs_i.i_zone;
+ if (!(tmp = *lp))
+ continue;
+ bh = getblk(inode->i_dev, tmp, XIAFS_ZSIZE(inode->i_sb));
+ if (i < DT_ZONE) {
+ brelse(bh);
+ goto repeat;
+ }
+ if ((bh && bh->b_count != 1) || tmp != *lp)
+ retry = 1;
+ else {
+ *lp = 0;
+ inode->i_dirt = 1;
+ inode->i_blocks-=2 << XIAFS_ZSHIFT(inode->i_sb);
+ xiafs_free_zone(inode->i_sb, tmp);
+ }
+ brelse(bh);
+ }
+ return retry;
+}
+
+static int trunc_indirect(struct inode * inode, int addr_off, u_long * lp)
+{
+
+#define INDT_ZONE (DT_ZONE - addr_off)
+
+ struct buffer_head * bh, * ind_bh;
+ int i, tmp;
+ u_long * indp;
+ int retry = 0;
+
+ if ( !(tmp=*lp) )
+ return 0;
+ ind_bh = bread(inode->i_dev, tmp, XIAFS_ZSIZE(inode->i_sb));
+ if (tmp != *lp) {
+ brelse(ind_bh);
+ return 1;
+ }
+ if (!ind_bh) {
+ *lp = 0;
+ return 0;
+ }
+repeat:
+ for (i = INDT_ZONE<0?0:INDT_ZONE; i < XIAFS_ADDRS_PER_Z(inode->i_sb); i++) {
+ if (i < INDT_ZONE)
+ goto repeat;
+ indp = i+(u_long *) ind_bh->b_data;
+ if (!(tmp=*indp))
+ continue;
+ bh = getblk(inode->i_dev, tmp, XIAFS_ZSIZE(inode->i_sb));
+ if (i < INDT_ZONE) {
+ brelse(bh);
+ goto repeat;
+ }
+ if ((bh && bh->b_count != 1) || tmp != *indp)
+ retry = 1;
+ else {
+ *indp = 0;
+ mark_buffer_dirty(ind_bh, 1);
+ inode->i_blocks-= 2 << XIAFS_ZSHIFT(inode->i_sb);
+ xiafs_free_zone(inode->i_sb, tmp);
+ }
+ brelse(bh);
+ }
+ indp = (u_long *) ind_bh->b_data;
+ for (i = 0; i < XIAFS_ADDRS_PER_Z(inode->i_sb) && !(*indp++); i++) ;
+ if (i >= XIAFS_ADDRS_PER_Z(inode->i_sb)) {
+ if (ind_bh->b_count != 1)
+ retry = 1;
+ else {
+ tmp = *lp;
+ *lp = 0;
+ inode->i_blocks-= 2 << XIAFS_ZSHIFT(inode->i_sb);
+ xiafs_free_zone(inode->i_sb, tmp);
+ }
+ }
+ brelse(ind_bh);
+ return retry;
+}
+
+static int trunc_dindirect(struct inode * inode)
+{
+
+#define DINDT_ZONE \
+ ((DT_ZONE-XIAFS_ADDRS_PER_Z(inode->i_sb)-8)>>XIAFS_ADDRS_PER_Z_BITS(inode->i_sb))
+
+ int i, tmp;
+ struct buffer_head * dind_bh;
+ u_long * dindp, * lp;
+ int retry = 0;
+
+ lp = &(inode->u.xiafs_i.i_dind_zone);
+ if (!(tmp = *lp))
+ return 0;
+ dind_bh = bread(inode->i_dev, tmp, XIAFS_ZSIZE(inode->i_sb));
+ if (tmp != *lp) {
+ brelse(dind_bh);
+ return 1;
+ }
+ if (!dind_bh) {
+ *lp = 0;
+ return 0;
+ }
+repeat:
+ for (i=DINDT_ZONE<0?0:DINDT_ZONE ; i < XIAFS_ADDRS_PER_Z(inode->i_sb) ; i ++) {
+ if (i < DINDT_ZONE)
+ goto repeat;
+ dindp = i+(u_long *) dind_bh->b_data;
+ retry |= trunc_indirect(inode,
+ 8+((1+i)<<XIAFS_ADDRS_PER_Z_BITS(inode->i_sb)),
+ dindp);
+ mark_buffer_dirty(dind_bh, 1);
+ }
+ dindp = (u_long *) dind_bh->b_data;
+ for (i = 0; i < XIAFS_ADDRS_PER_Z(inode->i_sb) && !(*dindp++); i++);
+ if (i >= XIAFS_ADDRS_PER_Z(inode->i_sb)) {
+ if (dind_bh->b_count != 1)
+ retry = 1;
+ else {
+ tmp = *lp;
+ *lp = 0;
+ inode->i_dirt = 1;
+ inode->i_blocks-=2 << XIAFS_ZSHIFT(inode->i_sb);
+ xiafs_free_zone(inode->i_sb, tmp);
+ }
+ }
+ brelse(dind_bh);
+ return retry;
+}
+
+void xiafs_truncate(struct inode * inode)
+{
+ int retry;
+
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+ S_ISLNK(inode->i_mode)))
+ return;
+ while (1) {
+ retry = trunc_direct(inode);
+ retry |= trunc_indirect(inode, 8, &(inode->u.xiafs_i.i_ind_zone));
+ retry |= trunc_dindirect(inode);
+ if (!retry)
+ break;
+ current->counter = 0;
+ schedule();
+ }
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ inode->i_dirt = 1;
+}
diff --git a/fs/xiafs/xiafs_mac.h b/fs/xiafs/xiafs_mac.h
new file mode 100644
index 000000000..05af6e42a
--- /dev/null
+++ b/fs/xiafs/xiafs_mac.h
@@ -0,0 +1,32 @@
+/*
+ * linux/fs/xiafs/xiafs_mac.h
+ *
+ * Copyright (C) Q. Frank Xia, 1993.
+ */
+
+extern char internal_error_message[];
+#define INTERN_ERR internal_error_message, __FILE__, __LINE__
+#define WHERE_ERR __FILE__, __LINE__
+
+#define XIAFS_ZSHIFT(sp) ((sp)->u.xiafs_sb.s_zone_shift)
+#define XIAFS_ZSIZE(sp) (BLOCK_SIZE << XIAFS_ZSHIFT(sp))
+#define XIAFS_ZSIZE_BITS(sp) (BLOCK_SIZE_BITS + XIAFS_ZSHIFT(sp))
+#define XIAFS_ADDRS_PER_Z(sp) (BLOCK_SIZE >> (2 - XIAFS_ZSHIFT(sp)))
+#define XIAFS_ADDRS_PER_Z_BITS(sp) (BLOCK_SIZE_BITS - 2 + XIAFS_ZSHIFT(sp))
+#define XIAFS_BITS_PER_Z(sp) (BLOCK_SIZE << (3 + XIAFS_ZSHIFT(sp)))
+#define XIAFS_BITS_PER_Z_BITS(sp) (BLOCK_SIZE_BITS + 3 + XIAFS_ZSHIFT(sp))
+#define XIAFS_INODES_PER_Z(sp) (_XIAFS_INODES_PER_BLOCK << XIAFS_ZSHIFT(sp))
+
+/* Use the most significant bytes of zone pointers to store block counter. */
+/* This is ugly, but it works. Note, We have another 7 bytes for "expansion". */
+
+#define XIAFS_GET_BLOCKS(row_ip, blocks) \
+ blocks=((((row_ip)->i_zone[0] >> 24) & 0xff )|\
+ (((row_ip)->i_zone[1] >> 16) & 0xff00 )|\
+ (((row_ip)->i_zone[2] >> 8) & 0xff0000 ) )
+
+/* XIAFS_PUT_BLOCKS should be called before saving zone pointers */
+#define XIAFS_PUT_BLOCKS(row_ip, blocks) \
+ (row_ip)->i_zone[2]=((blocks)<< 8) & 0xff000000;\
+ (row_ip)->i_zone[1]=((blocks)<<16) & 0xff000000;\
+ (row_ip)->i_zone[0]=((blocks)<<24) & 0xff000000