diff -ruN linux-source-2.6.24.orig/fs/asfs/Makefile linux-source-2.6.24/fs/asfs/Makefile --- linux-source-2.6.24.orig/fs/asfs/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-source-2.6.24/fs/asfs/Makefile 2008-12-14 23:05:05.000000000 +0300 @@ -0,0 +1,8 @@ +# +# Makefile for the linux asfs filesystem routines. +# + +obj-$(CONFIG_ASFS_FS) += asfs.o + +asfs-y += dir.o extents.o file.o inode.o namei.o nodes.o objects.o super.o symlink.o +asfs-$(CONFIG_ASFS_RW) += adminspace.o bitfuncs.o diff -ruN linux-source-2.6.24.orig/fs/asfs/namei.c linux-source-2.6.24/fs/asfs/namei.c --- linux-source-2.6.24.orig/fs/asfs/namei.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-source-2.6.24/fs/asfs/namei.c 2008-12-14 23:05:05.000000000 +0300 @@ -0,0 +1,197 @@ +/* + * + * Amiga Smart File System, Linux implementation + * version: 1.0beta10 + * + * Copyright (C) 2003,2004,2005 Marek 'March' Szyprowski <marek@xxxxxxxx> + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/fs.h> +#include <linux/buffer_head.h> +#include <linux/vfs.h> +#include <linux/string.h> +#include <linux/nls.h> +#include "asfs_fs.h" + +static inline u8 asfs_upperchar(u8 c) +{ + if ((c >= 224 && c <= 254 && c != 247) || (c >= 'a' && c <= 'z')) + c -= 32; + return (c); +} + +u8 asfs_lowerchar(u8 c) +{ + if ((c >= 192 && c <= 222 && c != 215) || (c >= 'A' && c <= 'Z')) + c += 32; + return (c); +} + +static inline u8 asfs_nls_upperchar(u8 c, struct nls_table *t) +{ + if (t) { + u8 nc = t->charset2upper[c]; + return nc ? nc : c; + } else + return asfs_upperchar(c); +} + +/* Check if the name is valid for a asfs object. */ + +inline int asfs_check_name(const u8 *name, int len) +{ + int i; + + if (len > ASFS_MAXFN) + return -ENAMETOOLONG; + + for (i = 0; i < len; i++) + if (name[i] < ' ' || name[i] == ':' || (name[i] > 0x7e && name[i] < 0xa0)) + return -EINVAL; + + return 0; +} + +/* Note: the dentry argument is the parent dentry. */ + +static int asfs_hash_dentry(struct dentry *dentry, struct qstr *qstr) +{ + struct super_block *sb = dentry->d_inode->i_sb; + const u8 *name = qstr->name; + unsigned long hash; + int i; + struct nls_table *nls_io = ASFS_SB(sb)->nls_io; + + i = asfs_check_name(qstr->name,qstr->len); + if (i) + return i; + + hash = init_name_hash(); + + if (ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE) + for (i=qstr->len; i > 0; name++, i--) + hash = partial_name_hash(*name, hash); + else + for (i=qstr->len; i > 0; name++, i--) + hash = partial_name_hash(asfs_nls_upperchar(*name, nls_io), hash); + + qstr->hash = end_name_hash(hash); + + return 0; +} + +static int asfs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) +{ + struct super_block *sb = dentry->d_inode->i_sb; + const u8 *aname = a->name; + const u8 *bname = b->name; + int len; + struct nls_table *nls_io = ASFS_SB(sb)->nls_io; + + /* 'a' is the qstr of an already existing dentry, so the name + * must be valid. 'b' must be validated first. + */ + + if (asfs_check_name(b->name,b->len)) + return 1; + + if (a->len != b->len) + return 1; + + if (ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE) { + for (len=a->len; len > 0; len--) + if (*aname++ != *bname++) + return 1; + } else { + for (len=a->len; len > 0; len--) + if (asfs_nls_upperchar(*aname++, nls_io) != asfs_nls_upperchar(*bname++, nls_io)) + return 1; + } + + return 0; +} + +struct dentry_operations asfs_dentry_operations = { + d_hash: asfs_hash_dentry, + d_compare: asfs_compare_dentry, +}; + +int asfs_namecmp(u8 *s, u8 *ct, int casesensitive, struct nls_table *t) +{ + if (casesensitive) { + while (*s == *ct && *ct != '\0' && *ct != '/') { + s++; + ct++; + } + } else { + while (asfs_nls_upperchar(*s, t) == asfs_nls_upperchar(*ct, t) && *ct != '\0' + && *ct != '/') { + s++; + ct++; + } + } + return (*s == '\0' && (*ct == '\0' || *ct == '/')) ? 0 : *ct - *s; +} + +u16 asfs_hash(u8 *name, int casesensitive) +{ + u16 hashval = 0; + while (name[hashval] != 0 && name[hashval] != '/') + hashval++; + if (casesensitive) { + u8 c = *name; + while (c != 0 && c != '/') { + hashval = hashval * 13 + c; + c = *++name; + } + } else { + u8 c = *name; + while (c != 0 && c != '/') { + hashval = hashval * 13 + asfs_upperchar(c); + c = *++name; + } + } + return hashval; +} + +void asfs_translate(u8 *to, u8 *from, struct nls_table *nls_to, struct nls_table *nls_from, int limit) +{ + wchar_t uni; + int i, len; + int from_len, to_len = limit; + + if (nls_to) { + from_len = strlen(from); + for (i=0; i < from_len && to_len > 1; ) { + len = nls_from->char2uni(&from[i], from_len-i, &uni); + if (len > 0) { + i += len; + len = nls_to->uni2char(uni, to, to_len); + if (len > 0) { + to += len; + to_len -= len; + } + } else + i++; + if (len < 0) { + *to++ = '?'; + to_len--; + } + } + *to = '\0'; + } else { + strncpy (to, from, limit); + to[limit-1] = '\0'; + } +} diff -ruN linux-source-2.6.24.orig/fs/asfs/nodes.c linux-source-2.6.24/fs/asfs/nodes.c --- linux-source-2.6.24.orig/fs/asfs/nodes.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-source-2.6.24/fs/asfs/nodes.c 2008-12-14 23:05:05.000000000 +0300 @@ -0,0 +1,455 @@ +/* + * + * Amiga Smart File System, Linux implementation + * version: 1.0beta7 + * + * This file contains some parts of the original amiga version of + * SmartFilesystem source code. + * + * SmartFilesystem is copyrighted (C) 2003 by: John Hendrikx, + * Ralph Schmidt, Emmanuel Lesueur, David Gerber and Marcin Kurek + * + * Adapted and modified by Marek 'March' Szyprowski <marek@xxxxxxxx> + * + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/fs.h> +#include <linux/buffer_head.h> +#include <linux/vfs.h> +#include "asfs_fs.h" + +#include <asm/byteorder.h> + +/* Finds a specific node by number. */ +int asfs_getnode(struct super_block *sb, u32 nodeno, struct buffer_head **ret_bh, struct fsObjectNode **ret_node) +{ + struct buffer_head *bh; + struct fsNodeContainer *nodecont; + u32 nodeindex = ASFS_SB(sb)->objectnoderoot; + + while ((bh = asfs_breadcheck(sb, nodeindex, ASFS_NODECONTAINER_ID))) { + nodecont = (struct fsNodeContainer *) bh->b_data; + + if (be32_to_cpu(nodecont->nodes) == 1) { + *ret_node = (struct fsObjectNode *) ((u8 *) nodecont->node + NODE_STRUCT_SIZE * (nodeno - be32_to_cpu(nodecont->nodenumber))); + *ret_bh = bh; + return 0; + } else { + u16 containerentry = (nodeno - be32_to_cpu(nodecont->nodenumber)) / be32_to_cpu(nodecont->nodes); + nodeindex = be32_to_cpu(nodecont->node[containerentry]) >> (sb->s_blocksize_bits - ASFS_BLCKFACCURACY); + } + asfs_brelse(bh); + } + if (bh == NULL) + return -EIO; + return -ENOENT; +} + +#ifdef CONFIG_ASFS_RW + + /* Looks for the parent of the passed-in buffer_head (fsNodeContainer) + starting from the root. It returns an error if any error occured. + If error is 0 and io_bh is NULL as well, then there was no parent (ie, + you asked parent of the root). Otherwise io_bh should contain the + parent of the passed-in NodeContainer. */ + +static int parentnodecontainer(struct super_block *sb, struct buffer_head **io_bh) +{ + u32 noderoot = ASFS_SB(sb)->objectnoderoot; + u32 childblock = be32_to_cpu(((struct fsBlockHeader *) (*io_bh)->b_data)->ownblock); + u32 nodenumber = be32_to_cpu(((struct fsNodeContainer *) (*io_bh)->b_data)->nodenumber); + int errorcode = 0; + + if (noderoot == childblock) { + *io_bh = NULL; + return 0; + } + + while ((*io_bh = asfs_breadcheck(sb, noderoot, ASFS_NODECONTAINER_ID))) { + struct fsNodeContainer *nc = (void *) (*io_bh)->b_data; + + if (be32_to_cpu(nc->nodes) == 1) { + /* We've descended the tree to a leaf NodeContainer, something + which should never happen if the passed-in io_bh had + contained a valid fsNodeContainer. */ + printk("ASFS: Failed to locate the parent NodeContainer - node tree is corrupted!\n"); + *io_bh = NULL; + return -EIO; + } else { + u16 containerentry = (nodenumber - be32_to_cpu(nc->nodenumber)) / be32_to_cpu(nc->nodes); + noderoot = be32_to_cpu(nc->node[containerentry]) >> (sb->s_blocksize_bits - ASFS_BLCKFACCURACY); + } + + if (noderoot == childblock) + break; + + asfs_brelse(*io_bh); + } + + if (*io_bh == NULL) + return -EIO; + + return errorcode; +} + + +static int isfull(struct super_block *sb, struct fsNodeContainer *nc) +{ + u32 *p = nc->node; + s16 n = NODECONT_BLOCK_COUNT; + + while (--n >= 0) { + if (*p == 0 || (be32_to_cpu(*p) & 0x00000001) == 0) { + break; + } + p++; + } + + return n < 0; +} + +static int markparentfull(struct super_block *sb, struct buffer_head *bh) +{ + u32 nodenumber = be32_to_cpu(((struct fsNodeContainer *) (bh->b_data))->nodenumber); + int errorcode; + + if ((errorcode = parentnodecontainer(sb, &bh)) == 0 && bh != 0) { + struct fsNodeContainer *nc = (void *) bh->b_data; + u16 containerentry = (nodenumber - be32_to_cpu(nc->nodenumber)) / be32_to_cpu(nc->nodes); + + nc->node[containerentry] = cpu_to_be32(be32_to_cpu(nc->node[containerentry]) | 0x00000001); + + asfs_bstore(sb, bh); + + if (isfull(sb, nc)) { /* This container now is full as well! Mark the next higher up container too then! */ + return markparentfull(sb, bh); + } + asfs_brelse(bh); + } + + return errorcode; +} + +static int addnewnodelevel(struct super_block *sb, u16 nodesize) +{ + struct buffer_head *bh; + u32 noderoot = ASFS_SB(sb)->objectnoderoot; + int errorcode; + + /* Adds a new level to the Node tree. */ + + asfs_debug("addnewnodelevel: Entry\n"); + + if ((bh = asfs_breadcheck(sb, noderoot, ASFS_NODECONTAINER_ID))) { + struct buffer_head *newbh; + u32 newblock; + + if ((errorcode = asfs_allocadminspace(sb, &newblock)) == 0 && (newbh = asfs_getzeroblk(sb, newblock))) { + struct fsNodeContainer *nc = (void *) bh->b_data; + struct fsNodeContainer *newnc = (void *) newbh->b_data; + + /* The newly allocated block will become a copy of the current root. */ + + newnc->bheader.id = cpu_to_be32(ASFS_NODECONTAINER_ID); + newnc->bheader.ownblock = cpu_to_be32(newblock); + newnc->nodenumber = nc->nodenumber; + newnc->nodes = nc->nodes; + memcpy(newnc->node, nc->node, sb->s_blocksize - sizeof(struct fsNodeContainer)); + + asfs_bstore(sb, newbh); + asfs_brelse(newbh); + + /* The current root will now be transformed into a new root. */ + + if (be32_to_cpu(nc->nodes) == 1) + nc->nodes = cpu_to_be32((sb->s_blocksize - sizeof(struct fsNodeContainer)) / nodesize); + else + nc->nodes = cpu_to_be32(be32_to_cpu(nc->nodes) * NODECONT_BLOCK_COUNT); + + nc->node[0] = cpu_to_be32((newblock << (sb->s_blocksize_bits - ASFS_BLCKFACCURACY)) + 1); /* Tree is full from that point! */ + memset(&nc->node[1], 0, sb->s_blocksize - sizeof(struct fsNodeContainer) - 4); + + asfs_bstore(sb, bh); + } + asfs_brelse(bh); + } else + errorcode = -EIO; + + return errorcode; +} + +static int createnodecontainer(struct super_block *sb, u32 nodenumber, u32 nodes, u32 * returned_block) +{ + struct buffer_head *bh; + int errorcode; + u32 newblock; + + asfs_debug("createnodecontainer: nodenumber = %u, nodes = %u\n", nodenumber, nodes); + + if ((errorcode = asfs_allocadminspace(sb, &newblock)) == 0 && (bh = asfs_getzeroblk(sb, newblock))) { + struct fsNodeContainer *nc = (void *) bh->b_data; + + nc->bheader.id = cpu_to_be32(ASFS_NODECONTAINER_ID); + nc->bheader.ownblock = cpu_to_be32(newblock); + + nc->nodenumber = cpu_to_be32(nodenumber); + nc->nodes = cpu_to_be32(nodes); + + asfs_bstore(sb, bh); + asfs_brelse(bh); + *returned_block = newblock; + } + + return errorcode; +} + + /* This function creates a new fsNode structure in a fsNodeContainer. If needed + it will create a new fsNodeContainers and a new fsNodeIndexContainer. */ + +int asfs_createnode(struct super_block *sb, struct buffer_head **returned_bh, struct fsNode **returned_node, u32 * returned_nodeno) +{ + u16 nodecount = (sb->s_blocksize - sizeof(struct fsNodeContainer)) / NODE_STRUCT_SIZE; + u32 noderoot = ASFS_SB(sb)->objectnoderoot; + u32 nodeindex = noderoot; + int errorcode = 0; + + while ((*returned_bh = asfs_breadcheck(sb, nodeindex, ASFS_NODECONTAINER_ID))) { + struct fsNodeContainer *nc = (void *) (*returned_bh)->b_data; + + if (be32_to_cpu(nc->nodes) == 1) { /* Is it a leaf-container? */ + struct fsNode *n; + s16 i = nodecount; + + n = (struct fsNode *) nc->node; + + while (i-- > 0) { + if (n->data == 0) + break; + + n = (struct fsNode *) ((u8 *) n + NODE_STRUCT_SIZE); + } + + if (i >= 0) { + /* Found an empty fsNode structure! */ + *returned_node = n; + *returned_nodeno = be32_to_cpu(nc->nodenumber) + ((u8 *) n - (u8 *) nc->node) / NODE_STRUCT_SIZE; + + asfs_debug("createnode: Created Node %d\n", *returned_nodeno); + + /* Below we continue to look through the NodeContainer block. We skip the entry + we found to be unused, and see if there are any more unused entries. If we + do not find any more unused entries then this container is now full. */ + + n = (struct fsNode *) ((u8 *) n + NODE_STRUCT_SIZE); + + while (i-- > 0) { + if (n->data == 0) + break; + + n = (struct fsNode *) ((u8 *) n + NODE_STRUCT_SIZE); + } + + if (i < 0) { + /* No more empty fsNode structures in this block. Mark parent full. */ + errorcode = markparentfull(sb, *returned_bh); + } + + return errorcode; + } else { + /* What happened now is that we found a leaf-container which was + completely filled. In practice this should only happen when there + is only a single NodeContainer (only this container), or when there + was an error in one of the full-bits in a higher level container. */ + + if (noderoot != nodeindex) { + /*** Hmmm... it looks like there was a damaged full-bit or something. + In this case we'd probably better call markcontainerfull. */ + + printk("ASFS: Couldn't find empty Node in NodeContainer while NodeIndexContainer indicated there should be one!\n"); + + errorcode = -ENOSPC; + break; + } else { + /* Container is completely filled. */ + + if ((errorcode = addnewnodelevel(sb, NODE_STRUCT_SIZE)) != 0) + return errorcode; + + nodeindex = noderoot; + } + } + } else { /* This isn't a leaf container */ + u32 *p = nc->node; + s16 i = NODECONT_BLOCK_COUNT; + + /* We've read a normal container */ + + while (i-- > 0) { + if (*p != 0 && (be32_to_cpu(*p) & 0x00000001) == 0) + break; + + p++; + } + + if (i >= 0) { + /* Found a not completely filled Container */ + + nodeindex = be32_to_cpu(*p) >> (sb->s_blocksize_bits - ASFS_BLCKFACCURACY); + } else { + /* Everything in the NodeIndexContainer was completely filled. There possibly + are some unused pointers in this block however. */ + + asfs_debug("createnode: NodeContainer at block has no empty Nodes.\n"); + + p = nc->node; + i = NODECONT_BLOCK_COUNT; + + while (i-- > 0) { + if (*p == 0) + break; + + p++; + } + + if (i >= 0) { + u32 newblock; + u32 nodes; + + /* Found an unused Container pointer */ + + if (be32_to_cpu(nc->nodes) == (sb->s_blocksize - sizeof(struct fsNodeContainer)) / NODE_STRUCT_SIZE) { + nodes = 1; + } else { + nodes = be32_to_cpu(nc->nodes) / NODECONT_BLOCK_COUNT; + } + + if ((errorcode = createnodecontainer(sb, be32_to_cpu(nc->nodenumber) + (p - nc->node) * be32_to_cpu(nc->nodes), nodes, &newblock)) != 0) { + break; + } + + *p = cpu_to_be32(newblock << (sb->s_blocksize_bits - ASFS_BLCKFACCURACY)); + + asfs_bstore(sb, *returned_bh); + } else { + /* Container is completely filled. This must be the top-level NodeIndex container + as otherwise the full-bit would have been wrong! */ + + if ((errorcode = addnewnodelevel(sb, NODE_STRUCT_SIZE)) != 0) + break; + + nodeindex = noderoot; + } + } + } + asfs_brelse(*returned_bh); + } + + if (*returned_bh == NULL) + return -EIO; + + return (errorcode); +} + +static int markparentempty(struct super_block *sb, struct buffer_head *bh) +{ + u32 nodenumber = be32_to_cpu(((struct fsNodeContainer *) bh->b_data)->nodenumber); + int errorcode; + + if ((errorcode = parentnodecontainer(sb, &bh)) == 0 && bh != 0) { + struct fsNodeContainer *nc = (void *) bh->b_data; + int wasfull; + u16 containerentry = (nodenumber - be32_to_cpu(nc->nodenumber)) / be32_to_cpu(nc->nodes); + + wasfull = isfull(sb, nc); + + nc->node[containerentry] = cpu_to_be32(be32_to_cpu(nc->node[containerentry]) & ~0x00000001); + + asfs_bstore(sb, bh); + + if (wasfull) { + /* This container was completely full before! Mark the next higher up container too then! */ + return markparentempty(sb, bh); + } + asfs_brelse(bh); + } + + return errorcode; +} + +static int freecontainer(struct super_block *sb, struct buffer_head *bh) +{ + u32 nodenumber = be32_to_cpu(((struct fsNodeContainer *) bh->b_data)->nodenumber); + int errorcode; + + if ((errorcode = parentnodecontainer(sb, &bh)) == 0 && bh != NULL) { /* This line also prevents the freeing of the noderoot. */ + struct fsNodeContainer *nc = (void *) bh->b_data; + u16 containerindex = (nodenumber - be32_to_cpu(nc->nodenumber)) / be32_to_cpu(nc->nodes); + + if ((errorcode = asfs_freeadminspace(sb, be32_to_cpu(nc->node[containerindex]) >> (sb->s_blocksize_bits - ASFS_BLCKFACCURACY))) == 0) { + u32 *p = nc->node; + s16 n = NODECONT_BLOCK_COUNT; + + nc->node[containerindex] = 0; + asfs_bstore(sb, bh); + + while (n-- > 0) + if (*p++ != 0) + break; + + if (n < 0) { /* This container is now completely empty! Free this NodeIndexContainer too then! */ + return freecontainer(sb, bh); + } + } + asfs_brelse(bh); + } + + return errorcode; +} + +static int internaldeletenode(struct super_block *sb, struct buffer_head *bh, struct fsNode *n) +{ + struct fsNodeContainer *nc = (void *) bh->b_data; + u16 nodecount = (sb->s_blocksize - sizeof(struct fsNodeContainer)) / NODE_STRUCT_SIZE; + s16 i = nodecount; + s16 empty = 0; + int errorcode = 0; + + n->data = 0; + n = (struct fsNode *) nc->node; + + while (i-- > 0) { + if (n->data == 0) + empty++; + + n = (struct fsNode *) ((u8 *) n + NODE_STRUCT_SIZE); + } + + asfs_bstore(sb, bh); + + if (empty == 1) /* NodeContainer was completely full before, so we need to mark it empty now. */ + errorcode = markparentempty(sb, bh); + else if (empty == nodecount) /* NodeContainer is now completely empty! Free it! */ + errorcode = freecontainer(sb, bh); + + return (errorcode); +} + +int asfs_deletenode(struct super_block *sb, u32 objectnode) +{ + struct buffer_head *bh; + struct fsObjectNode *on; + int errorcode; + + asfs_debug("deletenode: Deleting Node %d\n", objectnode); + + if ((errorcode = asfs_getnode(sb, objectnode, &bh, &on)) == 0) + errorcode = internaldeletenode(sb, bh, (struct fsNode *) on); + + asfs_brelse(bh); + return (errorcode); +} + +#endif -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html