patch-1.3.99 linux/fs/affs/amigaffs.c

Next file: linux/fs/affs/amigaffs.h
Previous file: linux/fs/affs/Makefile
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.98/linux/fs/affs/amigaffs.c linux/fs/affs/amigaffs.c
@@ -1,89 +1,57 @@
 /*
  *  linux/fs/affs/amigaffs.c
  *
- *  (C) 1996  Stefan Reinauer - Modified to compile as Module
+ *  (c) 1996  Hans-Joachim Widmaier - Modified for larger blocks.
  *
  *  (C) 1993  Ray Burr - Amiga FFS filesystem.
  *
  */
 
-
-#include <linux/module.h>
-
-#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/sched.h>
 #include <linux/affs_fs.h>
+#include <linux/string.h>
+#include <linux/locks.h>
 #include <linux/mm.h>
+#include <linux/amigaffs.h>
 
-#include "amigaffs.h"
+extern struct timezone sys_tz;
 
 /*
  * Functions for accessing Amiga-FFS structures.
  *
  */
 
-/* Get key entry number ENTRY_POS from the header block pointed to
-   by DATA.  If ENTRY_POS is invalid, -1 is returned.  This is
-   used to get entries from file and directory headers as well
-   as extension and root blocks.  In the current FFS specs, these
-   tables are defined to be the same size in all of these. */
-
-int affs_get_key_entry (int bsize, void *data, int entry_pos)
-{
-	struct dir_front *dir_front = (struct dir_front *)data;
-	int key, hash_table_size;
-
-	hash_table_size = MIDBLOCK_LONGS (bsize);
-	key = 0;
-	if (entry_pos >= 0 && entry_pos < hash_table_size)
-		key = swap_long (dir_front->hash_table[entry_pos]);
-
-	return key;
-}
-
 /* Find the next used hash entry at or after *HASH_POS in a directory's hash
    table.  *HASH_POS is assigned that entry's number.  DIR_DATA points to
    the directory header block in memory.  If there are no more entries,
    0 is returned.  Otherwise, the key number in the next used hash slot
    is returned. */
 
-int affs_find_next_hash_entry (int bsize, void *dir_data, int *hash_pos)
+int
+affs_find_next_hash_entry(int hsize, void *dir_data, ULONG *hash_pos)
 {
-	struct dir_front *dir_front = (struct dir_front *)dir_data;
-	int i, hash_table_size;
+	struct dir_front *dir_front = dir_data;
+	ULONG i;
 
-	hash_table_size = MIDBLOCK_LONGS (bsize);
-	if (*hash_pos < 0 || *hash_pos >= hash_table_size)
-		return -1;
-	for (i = *hash_pos; i < hash_table_size; i++)
-		if (dir_front->hash_table[i] != 0)
+	for (i = *hash_pos; i < hsize; i++)
+		if (dir_front->hashtable[i] != 0)
 			break;
-	if (i == hash_table_size)
+	if (i >= hsize)
 		return 0;
 	*hash_pos = i;
-	return swap_long (dir_front->hash_table[i]);
-}
-
-/* Get the hash_chain (next file header key in hash chain) entry from a
-   file header block in memory pointed to by FH_DATA. */
-
-int affs_get_fh_hash_link (int bsize, void *fh_data)
-{
-	struct file_end *file_end;
-	int key;
-
-	file_end = GET_END_PTR (struct file_end, fh_data, bsize);
-	key = swap_long (file_end->hash_chain);
-	return key;
+	return htonl(dir_front->hashtable[i]);
 }
 
 /* Set *NAME to point to the file name in a file header block in memory
    pointed to by FH_DATA.  The length of the name is returned. */
 
-int affs_get_file_name (int bsize, void *fh_data, char **name)
+int
+affs_get_file_name(int bsize, void *fh_data, char **name)
 {
 	struct file_end *file_end;
 
-	file_end = GET_END_PTR (struct file_end, fh_data, bsize);
+	file_end = GET_END_PTR(struct file_end, fh_data, bsize);
 	if (file_end->file_name[0] == 0
 	    || file_end->file_name[0] > 30) {
 		printk ("affs_get_file_name: OOPS! bad filename\n");
@@ -96,57 +64,210 @@
         return file_end->file_name[0];
 }
 
-/* Get the key number of the first extension block for the file
-   header pointed to by FH_DATA. */
+/* Find the predecessor in the hash chain */
 
-int affs_get_extension (int bsize, void *fh_data)
+int
+affs_fix_hash_pred(struct inode *startino, int startoffset, LONG key, LONG newkey)
 {
-	struct file_end *file_end;
-	int key;
+	struct buffer_head	*bh = NULL;
+	ULONG			 nextkey;
+	LONG			 ptype, stype;
+	int			 retval;
+
+	nextkey = startino->i_ino;
+	retval  = -ENOENT;
+	lock_super(startino->i_sb);
+	while (1) {
+		pr_debug("AFFS: fix_hash_pred(): next key=%d, offset=%d\n", nextkey, startoffset);
+		if (nextkey == 0)
+			break;
+		if (!(bh = affs_bread(startino->i_dev,nextkey,AFFS_I2BSIZE(startino))))
+			break;
+		if (affs_checksum_block(AFFS_I2BSIZE(startino),bh->b_data,&ptype,&stype)
+		    || ptype != T_SHORT || (stype != ST_FILE && stype != ST_USERDIR &&
+					    stype != ST_LINKFILE && stype != ST_LINKDIR &&
+					    stype != ST_ROOT && stype != ST_SOFTLINK)) {
+			printk("AFFS: bad block found in link chain (ptype=%d, stype=%d)\n",
+			       ptype,stype);
+			affs_brelse(bh);
+			break;
+		}
+		nextkey = htonl(((ULONG *)bh->b_data)[startoffset]);
+		if (nextkey == key) {
+			((ULONG *)bh->b_data)[startoffset] = newkey;
+			affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5);
+			mark_buffer_dirty(bh,1);
+			affs_brelse(bh);
+			retval = 0;
+			break;
+		}
+		affs_brelse(bh);
+		startoffset = AFFS_I2BSIZE(startino) / 4 - 4;
+	}
+	unlock_super(startino->i_sb);
 
-	file_end = GET_END_PTR (struct file_end, fh_data, bsize);
-	key = swap_long (file_end->extension);
-	return key;
+	return retval;
+}
+
+/* Remove inode from link chain */
+
+int
+affs_fix_link_pred(struct inode *startino, LONG key, LONG newkey)
+{
+	struct buffer_head	*bh = NULL;
+	ULONG			 nextkey;
+	ULONG			 offset;
+	LONG			 etype = 0;
+	LONG			 ptype, stype;
+	int			 retval;
+
+	offset  = AFFS_I2BSIZE(startino) / 4 - 10;
+	nextkey = startino->i_ino;
+	retval  = -ENOENT;
+	lock_super(startino->i_sb);
+	while (1) {
+		if (nextkey == 0)
+			break;
+		pr_debug("AFFS: find_link_pred(): next key=%d\n", nextkey));
+		if (!(bh = affs_bread(startino->i_dev,nextkey,AFFS_I2BSIZE(startino))))
+			break;
+		if (affs_checksum_block(AFFS_I2BSIZE(startino),bh->b_data,&ptype,&stype)
+		    || ptype != T_SHORT) {
+			affs_brelse(bh);
+			break;
+		}
+		if (!etype) {
+			if (stype != ST_FILE && stype != ST_USERDIR) {
+				affs_brelse(bh);
+				break;
+			}
+			if (stype == ST_FILE)
+				etype = ST_LINKFILE;
+			else
+				etype = ST_LINKDIR;
+		} else if (stype != etype) {
+			affs_brelse(bh);
+			retval = -EPERM;
+			break;
+		}
+		nextkey = htonl(((ULONG *)bh->b_data)[offset]);
+		if (nextkey == key) {
+			FILE_END(bh->b_data,startino)->link_chain = newkey;
+			affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5);
+			mark_buffer_dirty(bh,1);
+			affs_brelse(bh);
+			retval = 0;
+			break;
+		}
+		affs_brelse(bh);
+	}
+	unlock_super(startino->i_sb);
+	return retval;
 }
 
 /* Checksum a block, do various consistency checks and optionally return
    the blocks type number.  DATA points to the block.  If their pointers
    are non-null, *PTYPE and *STYPE are set to the primary and secondary
-   block types respectively.  Returns non-zero if the block is not
-   consistent. */
+   block types respectively, *HASHSIZE is set to the size of the hashtable
+   (which lets us calculate the block size).
+   Returns non-zero if the block is not consistent. */
 
-int affs_checksum_block (int bsize, void *data, int *ptype, int *stype)
+ULONG
+affs_checksum_block(int bsize, void *data, LONG *ptype, LONG *stype)
 {
+	ULONG sum;
+	ULONG *p;
+
+	bsize /= 4;
 	if (ptype)
-		*ptype = swap_long (((long *) data)[0]);
+		*ptype = htonl(((LONG *)data)[0]);
 	if (stype)
-		*stype = swap_long (((long *) data)[bsize / 4 - 1]);
-	return 0;
-}
+		*stype = htonl(((LONG *)data)[bsize - 1]);
 
-static struct file_system_type affs_fs_type = {
-        affs_read_super, "affs", 1, NULL
-};
+	sum    = 0;
+	p      = data;
+	while (bsize--)
+		sum += htonl(*p++);
+	return sum;
+}
 
-int init_affs_fs(void)
+void
+affs_fix_checksum(int bsize, void *data, int cspos)
 {
-        return register_filesystem(&affs_fs_type);
+	ULONG	 ocs;
+	ULONG	 cs;
+
+	cs   = affs_checksum_block(bsize,data,NULL,NULL);
+	ocs  = htonl (((ULONG *)data)[cspos]);
+	ocs -= cs;
+	((ULONG *)data)[cspos] = htonl(ocs);
 }
 
-#ifdef MODULE
-int init_module(void)
+void
+secs_to_datestamp(int secs, struct DateStamp *ds)
 {
-	int status;
+	ULONG	 days;
+	ULONG	 minute;
 
-	if ((status = init_affs_fs()) == 0)
-	        register_symtab(0);
-	return status;
+	secs -= sys_tz.tz_minuteswest * 60 +((8 * 365 + 2) * 24 * 60 * 60);
+	if (secs < 0)
+		secs = 0;
+	days    = secs / 86400;
+	secs   -= days * 86400;
+	minute  = secs / 60;
+	secs   -= minute * 60;
+
+	ds->ds_Days   = htonl(days);
+	ds->ds_Minute = htonl(minute);
+	ds->ds_Tick   = htonl(secs * 50);
 }
 
-void cleanup_module(void)
+int
+prot_to_mode(ULONG prot)
 {
-	unregister_filesystem(&affs_fs_type);
+	int	 mode = 0;
+
+	if (AFFS_UMAYWRITE(prot))
+		mode |= S_IWUSR;
+	if (AFFS_UMAYREAD(prot))
+		mode |= S_IRUSR;
+	if (AFFS_UMAYEXECUTE(prot))
+		mode |= S_IXUSR;
+	if (AFFS_GMAYWRITE(prot))
+		mode |= S_IWGRP;
+	if (AFFS_GMAYREAD(prot))
+		mode |= S_IRGRP;
+	if (AFFS_GMAYEXECUTE(prot))
+		mode |= S_IXGRP;
+	if (AFFS_OMAYWRITE(prot))
+		mode |= S_IWOTH;
+	if (AFFS_OMAYREAD(prot))
+		mode |= S_IROTH;
+	if (AFFS_OMAYEXECUTE(prot))
+		mode |= S_IXOTH;
+	
+	return mode;
 }
 
-#endif
+ULONG
+mode_to_prot(int mode)
+{
+	ULONG	 prot = 0;
 
+	if (mode & S_IXUSR)
+		prot |= FIBF_SCRIPT;
+	if (mode & S_IRUSR)
+		prot |= FIBF_READ;
+	if (mode & S_IWUSR)
+		prot |= FIBF_WRITE | FIBF_DELETE;
+	if (mode & S_IRGRP)
+		prot |= FIBF_GRP_READ;
+	if (mode & S_IWGRP)
+		prot |= FIBF_GRP_WRITE;
+	if (mode & S_IROTH)
+		prot |= FIBF_OTR_READ;
+	if (mode & S_IWOTH)
+		prot |= FIBF_OTR_WRITE;
+	
+	return prot;
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this