* [PATCH 7/9] Amiga SmartFileSystem
@ 2008-12-26 12:07 Pavel Fedin
0 siblings, 0 replies; 2+ messages in thread
From: Pavel Fedin @ 2008-12-26 12:07 UTC (permalink / raw)
To: linux-fsdevel
diff -ruN linux-source-2.6.24.orig/fs/asfs/objects.c linux-source-2.6.24/fs/asfs/objects.c
--- linux-source-2.6.24.orig/fs/asfs/objects.c 1970-01-01 03:00:00.000000000 +0300
+++ linux-source-2.6.24/fs/asfs/objects.c 2008-12-14 23:05:05.000000000 +0300
@@ -0,0 +1,765 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta11
+ *
+ * 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@amiga.pl>
+ *
+ */
+
+#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>
+
+struct fsObject *asfs_nextobject(struct fsObject *obj)
+{
+ int i;
+ u8 *p = obj->name;
+
+ for (i = 2; i > 0; p++)
+ if (*p == '\0')
+ i--;
+ if ((p - (u8 *) obj) & 0x01)
+ p++;
+
+ return ((struct fsObject *) p);
+}
+
+struct fsObject *asfs_find_obj_by_name(struct super_block *sb, struct fsObjectContainer *objcont, u8 * name)
+{
+ struct fsObject *obj;
+
+ obj = &(objcont->object[0]);
+ while (be32_to_cpu(obj->objectnode) > 0 && ((char *) obj - (char *) objcont) + sizeof(struct fsObject) + 2 < sb->s_blocksize) {
+ if (asfs_namecmp(obj->name, name, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE, NULL) == 0) {
+ asfs_debug("Object found! Node %u, Name %s, Type %x, inCont %u\n", be32_to_cpu(obj->objectnode), obj->name, obj->bits, be32_to_cpu(objcont->bheader.ownblock));
+ return obj;
+ }
+ obj = asfs_nextobject(obj);
+ }
+ return NULL;
+}
+
+#ifdef CONFIG_ASFS_RW
+
+static struct fsObject *find_obj_by_node(struct super_block *sb, struct fsObjectContainer *objcont, u32 objnode)
+{
+ struct fsObject *obj;
+
+ obj = &(objcont->object[0]);
+ while (be32_to_cpu(obj->objectnode) > 0 && ((char *) obj - (char *) objcont) + sizeof(struct fsObject) + 2 < sb->s_blocksize) {
+ if (be32_to_cpu(obj->objectnode) == objnode) {
+ return obj;
+ }
+ obj = asfs_nextobject(obj);
+ }
+ return NULL;
+}
+
+int asfs_readobject(struct super_block *sb, u32 objectnode, struct buffer_head **bh, struct fsObject **returned_object)
+{
+ struct fsObjectNode *on;
+ int errorcode;
+ u32 contblock;
+
+ asfs_debug("Seaching object - node %d\n", objectnode);
+
+ if ((errorcode = asfs_getnode(sb, objectnode, bh, &on)) != 0)
+ return errorcode;
+ contblock = be32_to_cpu(on->node.data);
+ asfs_brelse(*bh);
+
+ if (contblock > 0 && (*bh = asfs_breadcheck(sb, contblock, ASFS_OBJECTCONTAINER_ID))) {
+ *returned_object = find_obj_by_node(sb, (void *) (*bh)->b_data, objectnode);
+ if (*returned_object == NULL) {
+ brelse(*bh);
+ *bh = NULL;
+ return -ENOENT;
+ }
+ return 0;
+ } else
+ return -EIO;
+}
+
+static int removeobjectcontainer(struct super_block *sb, struct buffer_head *bh)
+{
+ struct fsObjectContainer *oc = (void *) bh->b_data;
+ int errorcode;
+ struct buffer_head *block;
+
+ asfs_debug("removeobjectcontainer: block %u\n", be32_to_cpu(oc->bheader.ownblock));
+
+ if (oc->next != 0 && oc->next != oc->bheader.ownblock) {
+ struct fsObjectContainer *next_oc;
+
+ if ((block = asfs_breadcheck(sb, be32_to_cpu(oc->next), ASFS_OBJECTCONTAINER_ID)) == NULL)
+ return -EIO;
+
+ next_oc = (void *) block->b_data;
+ next_oc->previous = oc->previous;
+
+ asfs_bstore(sb, block);
+ asfs_brelse(block);
+ }
+
+ if (oc->previous != 0 && oc->previous != oc->bheader.ownblock) {
+ struct fsObjectContainer *previous_oc;
+
+ if ((block = asfs_breadcheck(sb, be32_to_cpu(oc->previous), ASFS_OBJECTCONTAINER_ID)) == NULL)
+ return -EIO;
+
+ previous_oc = (void *) block->b_data;
+ previous_oc->next = oc->next;
+
+ asfs_bstore(sb, block);
+ asfs_brelse(block);
+ } else {
+ struct fsObject *parent_o;
+
+ if ((errorcode = asfs_readobject(sb, be32_to_cpu(oc->parent), &block, &parent_o)) != 0)
+ return (errorcode);
+
+ parent_o->object.dir.firstdirblock = oc->next;
+
+ asfs_bstore(sb, block);
+ asfs_brelse(block);
+ }
+
+ if ((errorcode = asfs_freeadminspace(sb, be32_to_cpu(oc->bheader.ownblock))) != 0)
+ return (errorcode);
+
+ return (0);
+}
+
+static int setrecycledinfodiff(struct super_block *sb, s32 deletedfiles, s32 deletedblocks)
+{
+ struct buffer_head *bh;
+
+ if ((bh = asfs_breadcheck(sb, ASFS_SB(sb)->rootobjectcontainer, ASFS_OBJECTCONTAINER_ID))) {
+ struct fsRootInfo *ri = (struct fsRootInfo *) ((u8 *) bh->b_data + sb->s_blocksize - sizeof(struct fsRootInfo));
+
+ ri->deletedfiles = cpu_to_be32(be32_to_cpu(ri->deletedfiles) + deletedfiles);
+ ri->deletedblocks = cpu_to_be32(be32_to_cpu(ri->deletedblocks) + deletedblocks);
+
+ asfs_bstore(sb, bh);
+ asfs_brelse(bh);
+ } else
+ return -EIO;
+ return 0;
+}
+
+ /* This function removes the fsObject structure passed in from the passed
+ buffer_head. If the ObjectContainer becomes completely empty it will be
+ delinked from the ObjectContainer chain and marked free for reuse.
+ This function doesn't delink the object from the hashchain! */
+
+static int simpleremoveobject(struct super_block *sb, struct buffer_head *bh, struct fsObject *o)
+{
+ struct fsObjectContainer *oc = (void *) bh->b_data;
+ int errorcode = 0;
+
+ asfs_debug("simpleremoveobject:\n");
+
+ if (be32_to_cpu(oc->parent) == ASFS_RECYCLEDNODE) {
+ /* This object is removed from the Recycled directory. */
+ if ((errorcode = setrecycledinfodiff(sb, -1, -((be32_to_cpu(o->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits))) != 0)
+ return errorcode;
+ }
+
+ if ((asfs_nextobject(oc->object))->name[0] == '\0')
+ errorcode = removeobjectcontainer(sb, bh);
+ else {
+ struct fsObject *nexto;
+ int objlen;
+
+ nexto = asfs_nextobject(o);
+ objlen = (u8 *) nexto - (u8 *) o;
+
+ memmove(o, nexto, sb->s_blocksize - ((u8 *) nexto - (u8 *) oc));
+ memset((u8 *) oc + sb->s_blocksize - objlen, 0, objlen);
+
+ asfs_bstore(sb, bh);
+ }
+ return errorcode;
+}
+
+/* This function delinks the passed in ObjectNode from its hash-chain. Handy when deleting
+ the object, or when renaming/moving it. */
+
+static int dehashobjectquick(struct super_block *sb, u32 objectnode, u8 *name, u32 parentobjectnode)
+{
+ struct fsObject *o;
+ int errorcode = 0;
+ struct buffer_head *block;
+
+ asfs_debug("dehashobject: Delinking object %d (=ObjectNode) from hashchain. Parentnode = %d\n", objectnode, parentobjectnode);
+
+ if ((errorcode = asfs_readobject(sb, parentobjectnode, &block, &o)) == 0 && o->object.dir.hashtable != 0) {
+ u32 hashtable = be32_to_cpu(o->object.dir.hashtable);
+ asfs_brelse(block);
+
+ if ((block = asfs_breadcheck(sb, hashtable, ASFS_HASHTABLE_ID))) {
+ struct buffer_head *node_bh;
+ struct fsObjectNode *onptr, on;
+ struct fsHashTable *ht = (void *) block->b_data;
+ u32 nexthash;
+
+ if ((errorcode = asfs_getnode(sb, objectnode, &node_bh, &onptr)) == 0) {
+ u16 hashchain;
+
+ asfs_debug("dehashobject: Read HashTable block of parent object of object to be delinked\n");
+
+ hashchain = HASHCHAIN(asfs_hash(name, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE));
+ nexthash = be32_to_cpu(ht->hashentry[hashchain]);
+
+ if (nexthash == objectnode) {
+ /* The hashtable directly points to the fsObject to be delinked. We simply
+ modify the Hashtable to point to the new nexthash entry. */
+
+ asfs_debug("dehashobject: The hashtable points directly to the to be delinked object\n");
+
+ ht->hashentry[hashchain] = onptr->next;
+ asfs_bstore(sb, block);
+ } else {
+ struct fsObjectNode *onsearch = 0;
+
+ on = *onptr;
+
+ asfs_debug("dehashobject: Walking through hashchain\n");
+
+ while (nexthash != 0 && nexthash != objectnode) {
+ asfs_brelse(node_bh);
+ if ((errorcode = asfs_getnode(sb, nexthash, &node_bh, &onsearch)) != 0)
+ break;
+ nexthash = be32_to_cpu(onsearch->next);
+ }
+
+ if (errorcode == 0) {
+ if (nexthash != 0) {
+ /* Previous fsObjectNode found in hash chain. Modify the fsObjectNode to 'skip' the
+ ObjectNode which is being delinked from the hash chain. */
+
+ onsearch->next = on.next;
+ asfs_bstore(sb, node_bh);
+ } else {
+ printk("ASFS: Hashchain of object %d is corrupt or incorrectly linked.", objectnode);
+
+ /*** This is strange. We have been looking for the fsObjectNode which is located before the
+ passed in fsObjectNode in the hash-chain. However, we never found the
+ fsObjectNode reffered to in the hash-chain! Has to be somekind
+ of internal error... */
+
+ errorcode = -ENOENT;
+ }
+ }
+ }
+ asfs_brelse(node_bh);
+ }
+ asfs_brelse(block);
+ }
+ }
+ return errorcode;
+}
+
+
+ /* This function removes an object from any directory. It takes care
+ of delinking the object from the hashchain and also frees the
+ objectnode number. */
+
+static int removeobject(struct super_block *sb, struct buffer_head *bh, struct fsObject *o)
+{
+ struct fsObjectContainer *oc = (void *) bh->b_data;
+ int errorcode;
+
+ asfs_debug("removeobject\n");
+
+ if ((errorcode = dehashobjectquick(sb, be32_to_cpu(o->objectnode), o->name, be32_to_cpu(oc->parent))) == 0) {
+ u32 objectnode = be32_to_cpu(o->objectnode);
+
+ if ((errorcode = simpleremoveobject(sb, bh, o)) == 0)
+ errorcode = asfs_deletenode(sb, objectnode);
+ }
+
+ return (errorcode);
+}
+
+ /* This function deletes the specified object. */
+int asfs_deleteobject(struct super_block *sb, struct buffer_head *bh, struct fsObject *o)
+{
+ int errorcode = 0;
+
+ asfs_debug("deleteobject: Entry -- deleting object %d (%s)\n", be32_to_cpu(o->objectnode), o->name);
+
+ if ((o->bits & OTYPE_DIR) == 0 || o->object.dir.firstdirblock == 0) {
+ u8 bits = o->bits;
+ u32 hashblckno = be32_to_cpu(o->object.dir.hashtable);
+ u32 extentbnode = be32_to_cpu(o->object.file.data);
+
+ if ((errorcode = removeobject(sb, bh, o)) == 0) {
+ if ((bits & OTYPE_LINK) != 0) {
+ asfs_debug("deleteobject: Object is soft link!\n");
+ errorcode = asfs_freeadminspace(sb, extentbnode);
+ } else if ((bits & OTYPE_DIR) != 0) {
+ asfs_debug("deleteobject: Object is a directory!\n");
+ errorcode = asfs_freeadminspace(sb, hashblckno);
+ } else {
+ asfs_debug("deleteobject: Object is a file\n");
+ if (extentbnode != 0)
+ errorcode = asfs_deleteextents(sb, extentbnode);
+ }
+ }
+ }
+
+ return (errorcode);
+}
+
+ /* This function takes a HashBlock pointer, an ObjectNode and an ObjectName.
+ If there is a hashblock, then this function will correctly link the object
+ into the hashchain. If there isn't a hashblock (=0) then this function
+ does nothing. */
+
+static int hashobject(struct super_block *sb, u32 hashblock, struct fsObjectNode *on, u32 nodeno, u8 *objectname)
+{
+ struct buffer_head *hash_bh;
+
+ asfs_debug("hashobject, using hashblock %d\n", hashblock);
+ if (hashblock == 0)
+ return 0;
+
+ if ((hash_bh = asfs_breadcheck(sb, hashblock, ASFS_HASHTABLE_ID))) {
+ struct fsHashTable *ht = (void *) hash_bh->b_data;
+ u32 nexthash;
+ u16 hashvalue, hashchain;
+
+ hashvalue = asfs_hash(objectname, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE);
+ hashchain = HASHCHAIN(hashvalue);
+ nexthash = be32_to_cpu(ht->hashentry[hashchain]);
+
+ ht->hashentry[hashchain] = cpu_to_be32(nodeno);
+
+ asfs_bstore(sb, hash_bh);
+ asfs_brelse(hash_bh);
+
+ on->next = cpu_to_be32(nexthash);
+ on->hash16 = cpu_to_be16(hashvalue);
+ } else
+ return -EIO;
+
+ return 0;
+}
+
+ /* This function returns a pointer to the first unused byte in
+ an ObjectContainer. */
+
+static u8 *emptyspaceinobjectcontainer(struct super_block *sb, struct fsObjectContainer *oc)
+{
+ struct fsObject *o = oc->object;
+ u8 *endadr;
+
+ endadr = (u8 *) oc + sb->s_blocksize - sizeof(struct fsObject) - 2;
+
+ while ((u8 *) o < endadr && o->name[0] != 0)
+ o = asfs_nextobject(o);
+
+ return (u8 *) o;
+}
+
+ /* This function will look in the directory indicated by io_o
+ for an ObjectContainer block which contains bytesneeded free
+ bytes. If none is found then this function simply creates a
+ new ObjectContainer and adds that to the indicated directory. */
+
+static int findobjectspace(struct super_block *sb, struct buffer_head **io_bh, struct fsObject **io_o, u32 bytesneeded)
+{
+ struct buffer_head *bhparent = *io_bh;
+ struct fsObject *oparent = *io_o;
+ struct buffer_head *bh;
+ u32 nextblock = be32_to_cpu(oparent->object.dir.firstdirblock);
+ int errorcode = 0;
+
+ asfs_debug("findobjectspace: Looking for %u bytes in directory with ObjectNode number %d (in block %d)\n", bytesneeded, be32_to_cpu((*io_o)->objectnode),
+ be32_to_cpu(((struct fsBlockHeader *) (*io_bh)->b_data)->ownblock));
+
+ while (nextblock != 0 && (bh = asfs_breadcheck(sb, nextblock, ASFS_OBJECTCONTAINER_ID))) {
+ struct fsObjectContainer *oc = (void *) bh->b_data;
+ u8 *emptyspace;
+
+ /* We need to find out how much free space this ObjectContainer has */
+
+ emptyspace = emptyspaceinobjectcontainer(sb, oc);
+
+ if ((u8 *) oc + sb->s_blocksize - emptyspace >= bytesneeded) {
+ /* We found enough space in one of the ObjectContainer blocks!!
+ We return a struct fsObject *. */
+ *io_bh = bh;
+ *io_o = (struct fsObject *) emptyspace;
+ break;
+ }
+ nextblock = be32_to_cpu(oc->next);
+ asfs_brelse(bh);
+ }
+
+ if (nextblock == 0) {
+ u32 newcontblock;
+ /* If we get here, we traversed the *entire* directory (ough!) and found no empty
+ space large enough for our entry. We allocate new space and add it to this
+ directory. */
+
+ if ((errorcode = asfs_allocadminspace(sb, &newcontblock)) == 0 && (bh = asfs_getzeroblk(sb, newcontblock))) {
+ struct fsObjectContainer *oc = (void *) bh->b_data;
+ struct buffer_head *bhnext;
+
+ asfs_debug("findobjectspace: No room was found, allocated new block at %u\n", newcontblock);
+
+ /* Allocated new block. We will now link it to the START of the directory chain
+ so the new free space can be found quickly when more entries need to be added. */
+
+ oc->bheader.id = cpu_to_be32(ASFS_OBJECTCONTAINER_ID);
+ oc->bheader.ownblock = cpu_to_be32(newcontblock);
+ oc->parent = oparent->objectnode;
+ oc->next = oparent->object.dir.firstdirblock;
+ oc->previous = 0;
+
+ oparent->object.dir.firstdirblock = cpu_to_be32(newcontblock);
+
+ asfs_bstore(sb, bhparent);
+
+ if (oc->next != 0 && (bhnext = asfs_breadcheck(sb, be32_to_cpu(oc->next), ASFS_OBJECTCONTAINER_ID))) {
+ struct fsObjectContainer *ocnext = (void *) bhnext->b_data;
+ ocnext->previous = cpu_to_be32(newcontblock);
+ asfs_bstore(sb, bhnext);
+ asfs_brelse(bhnext);
+ }
+
+ *io_bh = bh;
+ *io_o = oc->object;
+ }
+ }
+
+ asfs_debug("findobjectspace: new object will be in container block %u\n", be32_to_cpu(((struct fsBlockHeader *) (*io_bh)->b_data)->ownblock));
+
+ return (errorcode);
+}
+
+/* io_bh & io_o refer to the direct parent of the new object. Objectname is the
+ name of the new object (name only). Does not realese io_bh !!! */
+
+int asfs_createobject(struct super_block *sb, struct buffer_head **io_bh, struct fsObject **io_o, struct fsObject *src_o, u8 *objectname, int force)
+{
+ int errorcode;
+ u32 object_size;
+ u32 hashblock = be32_to_cpu((*io_o)->object.dir.hashtable);
+
+ asfs_debug("createobject: Creating object '%s' in dir '%s'.\n", objectname, (*io_o)->name);
+
+ if (!force && ASFS_SB(sb)->freeblocks < ASFS_ALWAYSFREE)
+ return -ENOSPC;
+
+ if (!force && be32_to_cpu((*io_o)->objectnode) == ASFS_RECYCLEDNODE)
+ return -EINVAL;
+
+ object_size = sizeof(struct fsObject) + strlen(objectname) + 2;
+
+ if ((errorcode = findobjectspace(sb, io_bh, io_o, object_size)) == 0) {
+ struct fsObject *o2 = *io_o;
+ u8 *name = o2->name;
+ u8 *objname = objectname;
+ struct buffer_head *node_bh;
+ struct fsObjectNode *on;
+ u32 nodeno;
+
+ **io_o = *src_o; /* Copying whole object data... */
+
+ while (*objname != 0) /* Copying name */
+ *name++ = *objname++;
+
+ *name++ = 0;
+ *name = 0; /* zero byte for comment */
+
+ if (o2->objectnode != 0) /* ObjectNode reuse or creation */
+ errorcode = asfs_getnode(sb, o2->objectnode, &node_bh, &on);
+ else {
+ if ((errorcode = asfs_createnode(sb, &node_bh, (struct fsNode **) &on, &nodeno)) == 0) {
+ on->hash16 = cpu_to_be16(asfs_hash(o2->name, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE));
+ o2->objectnode = cpu_to_be32(nodeno);
+ }
+ asfs_debug("createnode returned with errorcode: %d\n", errorcode);
+ }
+
+ if (errorcode == 0) { /* in io_bh there is a container with created object */
+ on->node.data = ((struct fsBlockHeader *) (*io_bh)->b_data)->ownblock;
+ if ((errorcode = hashobject(sb, hashblock, on, be32_to_cpu(o2->objectnode), objectname)) == 0) {
+ asfs_bstore(sb, node_bh);
+ asfs_brelse(node_bh);
+ } else
+ errorcode = -EIO;
+ }
+
+ if (errorcode == 0) { /* HashBlock reuse or creation:*/
+
+ if ((o2->bits & OTYPE_DIR) != 0 && o2->object.dir.hashtable == 0) {
+ struct buffer_head *hashbh;
+ u32 hashblock;
+
+ asfs_debug("creating Hashblock\n");
+
+ if ((errorcode = asfs_allocadminspace(sb, &hashblock)) == 0 && (hashbh = asfs_getzeroblk(sb, hashblock))) {
+ struct fsHashTable *ht = (void *) hashbh->b_data;
+
+ o2->object.dir.hashtable = cpu_to_be32(hashblock);
+
+ ht->bheader.id = cpu_to_be32(ASFS_HASHTABLE_ID);
+ ht->bheader.ownblock = cpu_to_be32(hashblock);
+ ht->parent = o2->objectnode;
+
+ asfs_bstore(sb, hashbh);
+ asfs_brelse(hashbh);
+ }
+ }
+ }
+
+ if (errorcode == 0) { /* SoftLink creation: */
+ if ((o2->bits & (OTYPE_LINK | OTYPE_HARDLINK)) == OTYPE_LINK && o2->object.file.data == 0) {
+ struct buffer_head *bh2;
+ u32 slinkblock;
+
+ if ((errorcode = asfs_allocadminspace(sb, &slinkblock)) == 0 && (bh2 = asfs_getzeroblk(sb, slinkblock))) {
+ struct fsSoftLink *sl = (void *) bh2->b_data;
+ o2->object.file.data = cpu_to_be32(slinkblock);
+ sl->bheader.id = cpu_to_be32(ASFS_SOFTLINK_ID);
+ sl->bheader.ownblock = cpu_to_be32(slinkblock);
+ sl->parent = o2->objectnode;
+ sl->next = 0;
+ sl->previous = 0;
+ asfs_bstore(sb, bh2);
+ asfs_brelse(bh2);
+ }
+ }
+ }
+ }
+ asfs_debug("createobject: done.\n");
+
+ return (errorcode);
+}
+
+ /* This function extends the file object 'o' with a number of blocks
+ (hopefully, if any blocks has been found!). Only new Extents will
+ be created -- the size of the file will not be altered, and changing
+ it is left up to the caller. If the file did not have any blocks
+ yet, then the o->object.file.data will be set to the first (new)
+ ExtentBNode. It returns the number of added blocks through
+ addedblocks pointer */
+
+int asfs_addblockstofile(struct super_block *sb, struct buffer_head *objbh, struct fsObject *o, u32 blocks, u32 * newspace, u32 * addedblocks)
+{
+ u32 lastextentbnode;
+ int errorcode = 0;
+ struct fsExtentBNode *ebnp;
+ struct buffer_head *block = NULL;
+
+
+ asfs_debug("extendblocksinfile: Trying to increasing number of blocks by %d.\n", blocks);
+
+ lastextentbnode = be32_to_cpu(o->object.file.data);
+
+ if (lastextentbnode != 0) {
+ while (lastextentbnode != 0 && errorcode == 0) {
+ if (block != NULL)
+ asfs_brelse(block);
+ errorcode = asfs_getextent(sb, lastextentbnode, &block, &ebnp);
+ lastextentbnode = be32_to_cpu(ebnp->next);
+ }
+ lastextentbnode = be32_to_cpu(ebnp->key);
+ }
+
+ if (errorcode == 0) {
+ u32 searchstart;
+
+ u32 found_block;
+ u32 found_blocks;
+
+ *addedblocks = 0;
+ *newspace = 0;
+
+ if (lastextentbnode != 0)
+ searchstart = be32_to_cpu(ebnp->key) + be16_to_cpu(ebnp->blocks);
+ else
+ searchstart = 0; //ASFS_SB(sb)->block_rovingblockptr;
+
+ if ((errorcode = asfs_findspace(sb, blocks, searchstart, searchstart, &found_block, &found_blocks)) != 0) {
+ asfs_brelse(block);
+ asfs_debug("extendblocksinfile: findspace returned %s\n", errorcode == -ENOSPC ? "ENOSPC" : "error");
+ return errorcode;
+ }
+
+ blocks = found_blocks;
+ errorcode = asfs_markspace(sb, found_block, found_blocks);
+ *addedblocks = found_blocks;
+ *newspace = found_block;
+
+ asfs_debug("extendblocksinfile: block = %u, lastextentbnode = %u, extentblocks = %d\n", found_block, lastextentbnode, blocks);
+
+ if ((errorcode = asfs_addblocks(sb, blocks, found_block, be32_to_cpu(o->objectnode), &lastextentbnode)) != 0) {
+ asfs_debug("extendblocksinfile: addblocks returned errorcode %d\n", errorcode);
+ return errorcode;
+ }
+
+ if (o->object.file.data == 0)
+ o->object.file.data = cpu_to_be32(lastextentbnode);
+ }
+
+ if (block)
+ asfs_brelse(block);
+ asfs_bstore(sb, objbh);
+
+ asfs_debug("addblockstofile: done. added %d blocks\n", *addedblocks);
+
+ return errorcode;
+}
+
+ /* The Object indicated by bh1 & o1, gets renamed to newname and placed
+ in the directory indicated by bhparent & oparent. */
+
+int asfs_renameobject(struct super_block *sb, struct buffer_head *bh1, struct fsObject *o1, struct buffer_head *bhparent, struct fsObject *oparent, u8 * newname)
+{
+ struct fsObject object;
+ u32 oldparentnode = be32_to_cpu(((struct fsObjectContainer *) bh1->b_data)->parent);
+ u8 oldname[107];
+ int errorcode;
+
+ asfs_debug("renameobject: Renaming '%s' to '%s' in dir '%s'\n", o1->name, newname, oparent->name);
+
+ object = *o1;
+ strcpy(oldname, o1->name);
+
+ if ((errorcode = dehashobjectquick(sb, be32_to_cpu(o1->objectnode), o1->name, oldparentnode)) == 0) {
+ u32 parentobjectnode = be32_to_cpu(oparent->objectnode);
+
+ if ((errorcode = simpleremoveobject(sb, bh1, o1)) == 0) {
+ struct buffer_head *bh2 = bhparent;
+ struct fsObject *o2;
+
+ /* oparent might changed after simpleremoveobject */
+ oparent = o2 = find_obj_by_node(sb, (struct fsObjectContainer *) bhparent->b_data, parentobjectnode);
+
+ /* In goes the Parent bh & o, out comes the New object's bh & o :-) */
+ if ((errorcode = asfs_createobject(sb, &bh2, &o2, &object, newname, TRUE)) == 0) {
+ asfs_bstore(sb, bh2);
+ if (be32_to_cpu(oparent->objectnode) == ASFS_RECYCLEDNODE) {
+ asfs_debug("renameobject: Updating recycled dir info\n");
+ if ((errorcode = setrecycledinfodiff(sb, 1, (be32_to_cpu(o2->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits)) != 0) {
+ brelse(bh2);
+ return errorcode;
+ }
+ }
+ brelse(bh2);
+ asfs_debug("renameobject: Succesfully created & stored new object.\n");
+ } else { /* recreate object in old place, maybe this will not fail, but who knows... */
+ asfs_debug("renameobject: Creating new object failed. Trying to recreate it in source directory.\n");
+ if (asfs_readobject(sb, oldparentnode, &bh1, &o1) == 0) {
+ struct buffer_head *bh2 = bh1;
+ if (asfs_createobject(sb, &bh2, &o1, &object, oldname, TRUE) == 0) {
+ asfs_bstore(sb, bh2);
+ if (oldparentnode == ASFS_RECYCLEDNODE) {
+ asfs_debug("renameobject: Updating recycled dir info\n");
+ setrecycledinfodiff(sb, 1, (be32_to_cpu(o1->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits);
+ }
+ brelse(bh2);
+ }
+ brelse(bh1);
+ }
+ }
+ }
+ }
+ return errorcode;
+}
+
+ /* Truncates the specified file to /newsize/ bytes */
+
+int asfs_truncateblocksinfile(struct super_block *sb, struct buffer_head *bh, struct fsObject *o, u32 newsize)
+{
+ struct buffer_head *ebh;
+ struct fsExtentBNode *ebn;
+ int errorcode;
+ u32 pos = 0;
+ u32 newblocks = (newsize + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+ u32 filedata = be32_to_cpu(o->object.file.data);
+ u32 eprev, ekey;
+ u16 eblocks;
+
+ asfs_debug("trucateblocksinfile: newsize %u\n", newsize);
+
+ if (filedata == 0)
+ return 0;
+
+ for (;;) {
+ if ((errorcode = asfs_getextent(sb, filedata, &ebh, &ebn)) != 0)
+ return errorcode;
+ if (pos + be16_to_cpu(ebn->blocks) >= newblocks)
+ break;
+ pos += be16_to_cpu(ebn->blocks);
+ if ((filedata = be32_to_cpu(ebn->next)) == 0)
+ break;
+ asfs_brelse(ebh);
+ };
+
+ eblocks = newblocks - pos;
+ ekey = be32_to_cpu(ebn->key);
+ eprev = be32_to_cpu(ebn->prev);
+
+ if (be16_to_cpu(ebn->blocks) < eblocks) {
+ printk("ASFS: Extent chain is too short or damaged!\n");
+ asfs_brelse(ebh);
+ return -ENOENT;
+ }
+ if (be16_to_cpu(ebn->blocks) - eblocks > 0 && (errorcode = asfs_freespace(sb, be32_to_cpu(ebn->key) + eblocks, be16_to_cpu(ebn->blocks) - eblocks)) != 0) {
+ asfs_brelse(ebh);
+ return errorcode;
+ }
+ if (be32_to_cpu(ebn->next) > 0 && (errorcode = asfs_deleteextents(sb, be32_to_cpu(ebn->next))) != 0) {
+ asfs_brelse(ebh);
+ return errorcode;
+ }
+ ebn->blocks = cpu_to_be16(eblocks);
+ ebn->next = 0;
+ asfs_bstore(sb, ebh);
+
+ if (eblocks == 0) {
+ if (eprev & MSB_MASK) {
+ o->object.file.data = 0;
+ asfs_bstore(sb, bh);
+ } else {
+ struct buffer_head *ebhp;
+ struct fsExtentBNode *ebnp;
+
+ if ((errorcode = asfs_getextent(sb, eprev & !MSB_MASK, &ebhp, &ebnp)) != 0) {
+ asfs_brelse(ebh);
+ return errorcode;
+ }
+
+ ebnp->next = 0;
+ asfs_bstore(sb, ebhp);
+ asfs_brelse(ebhp);
+ }
+ if ((errorcode = asfs_deletebnode(sb, ebh, ekey)) != 0) {
+ asfs_brelse(ebh);
+ return errorcode;
+ }
+ }
+ asfs_brelse(ebh);
+
+ return 0;
+}
+#endif
^ permalink raw reply [flat|nested] 2+ messages in thread* [PATCH 7/9] Amiga SmartFileSystem
@ 2009-02-09 6:56 Pavel Fedin
0 siblings, 0 replies; 2+ messages in thread
From: Pavel Fedin @ 2009-02-09 6:56 UTC (permalink / raw)
To: linux-fsdevel
diff -ruN linux-source-2.6.24.orig/fs/asfs/objects.c
linux-source-2.6.24/fs/asfs/objects.c
--- linux-source-2.6.24.orig/fs/asfs/objects.c 1970-01-01
03:00:00.000000000 +0300
+++ linux-source-2.6.24/fs/asfs/objects.c 2008-12-14
23:05:05.000000000 +0300
@@ -0,0 +1,765 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta11
+ *
+ * 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@amiga.pl>
+ *
+ */
+
+#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>
+
+struct fsObject *asfs_nextobject(struct fsObject *obj)
+{
+ int i;
+ u8 *p = obj->name;
+
+ for (i = 2; i > 0; p++)
+ if (*p == '\0')
+ i--;
+ if ((p - (u8 *) obj) & 0x01)
+ p++;
+
+ return ((struct fsObject *) p);
+}
+
+struct fsObject *asfs_find_obj_by_name(struct super_block *sb, struct
fsObjectContainer *objcont, u8 * name)
+{
+ struct fsObject *obj;
+
+ obj = &(objcont->object[0]);
+ while (be32_to_cpu(obj->objectnode) > 0 && ((char *) obj -
(char *) objcont) + sizeof(struct fsObject) + 2 < sb->s_blocksize) {
+ if (asfs_namecmp(obj->name, name, ASFS_SB(sb)->flags &
ASFS_ROOTBITS_CASESENSITIVE, NULL) == 0) {
+ asfs_debug("Object found! Node %u, Name %s,
Type %x, inCont %u\n", be32_to_cpu(obj->objectnode), obj->name,
obj->bits, be32_to_cpu(objcont->bheader.ownblock));
+ return obj;
+ }
+ obj = asfs_nextobject(obj);
+ }
+ return NULL;
+}
+
+#ifdef CONFIG_ASFS_RW
+
+static struct fsObject *find_obj_by_node(struct super_block *sb,
struct fsObjectContainer *objcont, u32 objnode)
+{
+ struct fsObject *obj;
+
+ obj = &(objcont->object[0]);
+ while (be32_to_cpu(obj->objectnode) > 0 && ((char *) obj -
(char *) objcont) + sizeof(struct fsObject) + 2 < sb->s_blocksize) {
+ if (be32_to_cpu(obj->objectnode) == objnode) {
+ return obj;
+ }
+ obj = asfs_nextobject(obj);
+ }
+ return NULL;
+}
+
+int asfs_readobject(struct super_block *sb, u32 objectnode, struct
buffer_head **bh, struct fsObject **returned_object)
+{
+ struct fsObjectNode *on;
+ int errorcode;
+ u32 contblock;
+
+ asfs_debug("Seaching object - node %d\n", objectnode);
+
+ if ((errorcode = asfs_getnode(sb, objectnode, bh, &on)) != 0)
+ return errorcode;
+ contblock = be32_to_cpu(on->node.data);
+ asfs_brelse(*bh);
+
+ if (contblock > 0 && (*bh = asfs_breadcheck(sb, contblock,
ASFS_OBJECTCONTAINER_ID))) {
+ *returned_object = find_obj_by_node(sb, (void *)
(*bh)->b_data, objectnode);
+ if (*returned_object == NULL) {
+ brelse(*bh);
+ *bh = NULL;
+ return -ENOENT;
+ }
+ return 0;
+ } else
+ return -EIO;
+}
+
+static int removeobjectcontainer(struct super_block *sb, struct
buffer_head *bh)
+{
+ struct fsObjectContainer *oc = (void *) bh->b_data;
+ int errorcode;
+ struct buffer_head *block;
+
+ asfs_debug("removeobjectcontainer: block %u\n",
be32_to_cpu(oc->bheader.ownblock));
+
+ if (oc->next != 0 && oc->next != oc->bheader.ownblock) {
+ struct fsObjectContainer *next_oc;
+
+ if ((block = asfs_breadcheck(sb,
be32_to_cpu(oc->next), ASFS_OBJECTCONTAINER_ID)) == NULL)
+ return -EIO;
+
+ next_oc = (void *) block->b_data;
+ next_oc->previous = oc->previous;
+
+ asfs_bstore(sb, block);
+ asfs_brelse(block);
+ }
+
+ if (oc->previous != 0 && oc->previous != oc->bheader.ownblock) {
+ struct fsObjectContainer *previous_oc;
+
+ if ((block = asfs_breadcheck(sb,
be32_to_cpu(oc->previous), ASFS_OBJECTCONTAINER_ID)) == NULL)
+ return -EIO;
+
+ previous_oc = (void *) block->b_data;
+ previous_oc->next = oc->next;
+
+ asfs_bstore(sb, block);
+ asfs_brelse(block);
+ } else {
+ struct fsObject *parent_o;
+
+ if ((errorcode = asfs_readobject(sb,
be32_to_cpu(oc->parent), &block, &parent_o)) != 0)
+ return (errorcode);
+
+ parent_o->object.dir.firstdirblock = oc->next;
+
+ asfs_bstore(sb, block);
+ asfs_brelse(block);
+ }
+
+ if ((errorcode = asfs_freeadminspace(sb,
be32_to_cpu(oc->bheader.ownblock))) != 0)
+ return (errorcode);
+
+ return (0);
+}
+
+static int setrecycledinfodiff(struct super_block *sb, s32
deletedfiles, s32 deletedblocks)
+{
+ struct buffer_head *bh;
+
+ if ((bh = asfs_breadcheck(sb,
ASFS_SB(sb)->rootobjectcontainer, ASFS_OBJECTCONTAINER_ID))) {
+ struct fsRootInfo *ri = (struct fsRootInfo *) ((u8 *)
bh->b_data + sb->s_blocksize - sizeof(struct fsRootInfo));
+
+ ri->deletedfiles =
cpu_to_be32(be32_to_cpu(ri->deletedfiles) + deletedfiles);
+ ri->deletedblocks =
cpu_to_be32(be32_to_cpu(ri->deletedblocks) + deletedblocks);
+
+ asfs_bstore(sb, bh);
+ asfs_brelse(bh);
+ } else
+ return -EIO;
+ return 0;
+}
+
+ /* This function removes the fsObject structure passed in from
the passed
+ buffer_head. If the ObjectContainer becomes completely
empty it will be
+ delinked from the ObjectContainer chain and marked free for reuse.
+ This function doesn't delink the object from the hashchain! */
+
+static int simpleremoveobject(struct super_block *sb, struct
buffer_head *bh, struct fsObject *o)
+{
+ struct fsObjectContainer *oc = (void *) bh->b_data;
+ int errorcode = 0;
+
+ asfs_debug("simpleremoveobject:\n");
+
+ if (be32_to_cpu(oc->parent) == ASFS_RECYCLEDNODE) {
+ /* This object is removed from the Recycled directory. */
+ if ((errorcode = setrecycledinfodiff(sb, -1,
-((be32_to_cpu(o->object.file.size) + sb->s_blocksize - 1) >>
sb->s_blocksize_bits))) != 0)
+ return errorcode;
+ }
+
+ if ((asfs_nextobject(oc->object))->name[0] == '\0')
+ errorcode = removeobjectcontainer(sb, bh);
+ else {
+ struct fsObject *nexto;
+ int objlen;
+
+ nexto = asfs_nextobject(o);
+ objlen = (u8 *) nexto - (u8 *) o;
+
+ memmove(o, nexto, sb->s_blocksize - ((u8 *) nexto - (u8 *) oc));
+ memset((u8 *) oc + sb->s_blocksize - objlen, 0, objlen);
+
+ asfs_bstore(sb, bh);
+ }
+ return errorcode;
+}
+
+/* This function delinks the passed in ObjectNode from its
hash-chain. Handy when deleting
+ the object, or when renaming/moving it. */
+
+static int dehashobjectquick(struct super_block *sb, u32 objectnode,
u8 *name, u32 parentobjectnode)
+{
+ struct fsObject *o;
+ int errorcode = 0;
+ struct buffer_head *block;
+
+ asfs_debug("dehashobject: Delinking object %d (=ObjectNode)
from hashchain. Parentnode = %d\n", objectnode, parentobjectnode);
+
+ if ((errorcode = asfs_readobject(sb, parentobjectnode, &block,
&o)) == 0 && o->object.dir.hashtable != 0) {
+ u32 hashtable = be32_to_cpu(o->object.dir.hashtable);
+ asfs_brelse(block);
+
+ if ((block = asfs_breadcheck(sb, hashtable,
ASFS_HASHTABLE_ID))) {
+ struct buffer_head *node_bh;
+ struct fsObjectNode *onptr, on;
+ struct fsHashTable *ht = (void *) block->b_data;
+ u32 nexthash;
+
+ if ((errorcode = asfs_getnode(sb, objectnode,
&node_bh, &onptr)) == 0) {
+ u16 hashchain;
+
+ asfs_debug("dehashobject: Read
HashTable block of parent object of object to be delinked\n");
+
+ hashchain = HASHCHAIN(asfs_hash(name,
ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE));
+ nexthash =
be32_to_cpu(ht->hashentry[hashchain]);
+
+ if (nexthash == objectnode) {
+ /* The hashtable directly
points to the fsObject to be delinked. We simply
+ modify the Hashtable to
point to the new nexthash entry. */
+
+ asfs_debug("dehashobject: The
hashtable points directly to the to be delinked object\n");
+
+ ht->hashentry[hashchain] = onptr->next;
+ asfs_bstore(sb, block);
+ } else {
+ struct fsObjectNode *onsearch = 0;
+
+ on = *onptr;
+
+ asfs_debug("dehashobject:
Walking through hashchain\n");
+
+ while (nexthash != 0 &&
nexthash != objectnode) {
+ asfs_brelse(node_bh);
+ if ((errorcode =
asfs_getnode(sb, nexthash, &node_bh, &onsearch)) != 0)
+ break;
+ nexthash =
be32_to_cpu(onsearch->next);
+ }
+
+ if (errorcode == 0) {
+ if (nexthash != 0) {
+ /* Previous
fsObjectNode found in hash chain. Modify the fsObjectNode to 'skip'
the
+ ObjectNode
which is being delinked from the hash chain. */
+
+ onsearch->next
= on.next;
+
asfs_bstore(sb, node_bh);
+ } else {
+ printk("ASFS:
Hashchain of object %d is corrupt or incorrectly linked.",
objectnode);
+
+ /*** This is
strange. We have been looking for the fsObjectNode which is located
before the
+ passed in
fsObjectNode in the hash-chain. However, we never found the
+
fsObjectNode reffered to in the hash-chain! Has to be somekind
+ of
internal error... */
+
+ errorcode = -ENOENT;
+ }
+ }
+ }
+ asfs_brelse(node_bh);
+ }
+ asfs_brelse(block);
+ }
+ }
+ return errorcode;
+}
+
+
+ /* This function removes an object from any directory. It takes care
+ of delinking the object from the hashchain and also frees the
+ objectnode number. */
+
+static int removeobject(struct super_block *sb, struct buffer_head
*bh, struct fsObject *o)
+{
+ struct fsObjectContainer *oc = (void *) bh->b_data;
+ int errorcode;
+
+ asfs_debug("removeobject\n");
+
+ if ((errorcode = dehashobjectquick(sb,
be32_to_cpu(o->objectnode), o->name, be32_to_cpu(oc->parent))) == 0) {
+ u32 objectnode = be32_to_cpu(o->objectnode);
+
+ if ((errorcode = simpleremoveobject(sb, bh, o)) == 0)
+ errorcode = asfs_deletenode(sb, objectnode);
+ }
+
+ return (errorcode);
+}
+
+ /* This function deletes the specified object. */
+int asfs_deleteobject(struct super_block *sb, struct buffer_head *bh,
struct fsObject *o)
+{
+ int errorcode = 0;
+
+ asfs_debug("deleteobject: Entry -- deleting object %d (%s)\n",
be32_to_cpu(o->objectnode), o->name);
+
+ if ((o->bits & OTYPE_DIR) == 0 || o->object.dir.firstdirblock == 0) {
+ u8 bits = o->bits;
+ u32 hashblckno = be32_to_cpu(o->object.dir.hashtable);
+ u32 extentbnode = be32_to_cpu(o->object.file.data);
+
+ if ((errorcode = removeobject(sb, bh, o)) == 0) {
+ if ((bits & OTYPE_LINK) != 0) {
+ asfs_debug("deleteobject: Object is
soft link!\n");
+ errorcode = asfs_freeadminspace(sb,
extentbnode);
+ } else if ((bits & OTYPE_DIR) != 0) {
+ asfs_debug("deleteobject: Object is a
directory!\n");
+ errorcode = asfs_freeadminspace(sb, hashblckno);
+ } else {
+ asfs_debug("deleteobject: Object is a file\n");
+ if (extentbnode != 0)
+ errorcode =
asfs_deleteextents(sb, extentbnode);
+ }
+ }
+ }
+
+ return (errorcode);
+}
+
+ /* This function takes a HashBlock pointer, an ObjectNode and
an ObjectName.
+ If there is a hashblock, then this function will correctly
link the object
+ into the hashchain. If there isn't a hashblock (=0) then
this function
+ does nothing. */
+
+static int hashobject(struct super_block *sb, u32 hashblock, struct
fsObjectNode *on, u32 nodeno, u8 *objectname)
+{
+ struct buffer_head *hash_bh;
+
+ asfs_debug("hashobject, using hashblock %d\n", hashblock);
+ if (hashblock == 0)
+ return 0;
+
+ if ((hash_bh = asfs_breadcheck(sb, hashblock, ASFS_HASHTABLE_ID))) {
+ struct fsHashTable *ht = (void *) hash_bh->b_data;
+ u32 nexthash;
+ u16 hashvalue, hashchain;
+
+ hashvalue = asfs_hash(objectname, ASFS_SB(sb)->flags &
ASFS_ROOTBITS_CASESENSITIVE);
+ hashchain = HASHCHAIN(hashvalue);
+ nexthash = be32_to_cpu(ht->hashentry[hashchain]);
+
+ ht->hashentry[hashchain] = cpu_to_be32(nodeno);
+
+ asfs_bstore(sb, hash_bh);
+ asfs_brelse(hash_bh);
+
+ on->next = cpu_to_be32(nexthash);
+ on->hash16 = cpu_to_be16(hashvalue);
+ } else
+ return -EIO;
+
+ return 0;
+}
+
+ /* This function returns a pointer to the first unused byte in
+ an ObjectContainer. */
+
+static u8 *emptyspaceinobjectcontainer(struct super_block *sb, struct
fsObjectContainer *oc)
+{
+ struct fsObject *o = oc->object;
+ u8 *endadr;
+
+ endadr = (u8 *) oc + sb->s_blocksize - sizeof(struct fsObject) - 2;
+
+ while ((u8 *) o < endadr && o->name[0] != 0)
+ o = asfs_nextobject(o);
+
+ return (u8 *) o;
+}
+
+ /* This function will look in the directory indicated by io_o
+ for an ObjectContainer block which contains bytesneeded free
+ bytes. If none is found then this function simply creates a
+ new ObjectContainer and adds that to the indicated directory. */
+
+static int findobjectspace(struct super_block *sb, struct buffer_head
**io_bh, struct fsObject **io_o, u32 bytesneeded)
+{
+ struct buffer_head *bhparent = *io_bh;
+ struct fsObject *oparent = *io_o;
+ struct buffer_head *bh;
+ u32 nextblock = be32_to_cpu(oparent->object.dir.firstdirblock);
+ int errorcode = 0;
+
+ asfs_debug("findobjectspace: Looking for %u bytes in directory
with ObjectNode number %d (in block %d)\n", bytesneeded,
be32_to_cpu((*io_o)->objectnode),
+ be32_to_cpu(((struct fsBlockHeader *)
(*io_bh)->b_data)->ownblock));
+
+ while (nextblock != 0 && (bh = asfs_breadcheck(sb, nextblock,
ASFS_OBJECTCONTAINER_ID))) {
+ struct fsObjectContainer *oc = (void *) bh->b_data;
+ u8 *emptyspace;
+
+ /* We need to find out how much free space this
ObjectContainer has */
+
+ emptyspace = emptyspaceinobjectcontainer(sb, oc);
+
+ if ((u8 *) oc + sb->s_blocksize - emptyspace >= bytesneeded) {
+ /* We found enough space in one of the
ObjectContainer blocks!!
+ We return a struct fsObject *. */
+ *io_bh = bh;
+ *io_o = (struct fsObject *) emptyspace;
+ break;
+ }
+ nextblock = be32_to_cpu(oc->next);
+ asfs_brelse(bh);
+ }
+
+ if (nextblock == 0) {
+ u32 newcontblock;
+ /* If we get here, we traversed the *entire* directory
(ough!) and found no empty
+ space large enough for our entry. We allocate new
space and add it to this
+ directory. */
+
+ if ((errorcode = asfs_allocadminspace(sb,
&newcontblock)) == 0 && (bh = asfs_getzeroblk(sb, newcontblock))) {
+ struct fsObjectContainer *oc = (void *) bh->b_data;
+ struct buffer_head *bhnext;
+
+ asfs_debug("findobjectspace: No room was
found, allocated new block at %u\n", newcontblock);
+
+ /* Allocated new block. We will now link it
to the START of the directory chain
+ so the new free space can be found quickly
when more entries need to be added. */
+
+ oc->bheader.id = cpu_to_be32(ASFS_OBJECTCONTAINER_ID);
+ oc->bheader.ownblock = cpu_to_be32(newcontblock);
+ oc->parent = oparent->objectnode;
+ oc->next = oparent->object.dir.firstdirblock;
+ oc->previous = 0;
+
+ oparent->object.dir.firstdirblock =
cpu_to_be32(newcontblock);
+
+ asfs_bstore(sb, bhparent);
+
+ if (oc->next != 0 && (bhnext =
asfs_breadcheck(sb, be32_to_cpu(oc->next), ASFS_OBJECTCONTAINER_ID)))
{
+ struct fsObjectContainer *ocnext =
(void *) bhnext->b_data;
+ ocnext->previous = cpu_to_be32(newcontblock);
+ asfs_bstore(sb, bhnext);
+ asfs_brelse(bhnext);
+ }
+
+ *io_bh = bh;
+ *io_o = oc->object;
+ }
+ }
+
+ asfs_debug("findobjectspace: new object will be in container
block %u\n", be32_to_cpu(((struct fsBlockHeader *)
(*io_bh)->b_data)->ownblock));
+
+ return (errorcode);
+}
+
+/* io_bh & io_o refer to the direct parent of the new object.
Objectname is the
+ name of the new object (name only). Does not realese io_bh !!! */
+
+int asfs_createobject(struct super_block *sb, struct buffer_head
**io_bh, struct fsObject **io_o, struct fsObject *src_o, u8
*objectname, int force)
+{
+ int errorcode;
+ u32 object_size;
+ u32 hashblock = be32_to_cpu((*io_o)->object.dir.hashtable);
+
+ asfs_debug("createobject: Creating object '%s' in dir
'%s'.\n", objectname, (*io_o)->name);
+
+ if (!force && ASFS_SB(sb)->freeblocks < ASFS_ALWAYSFREE)
+ return -ENOSPC;
+
+ if (!force && be32_to_cpu((*io_o)->objectnode) == ASFS_RECYCLEDNODE)
+ return -EINVAL;
+
+ object_size = sizeof(struct fsObject) + strlen(objectname) + 2;
+
+ if ((errorcode = findobjectspace(sb, io_bh, io_o, object_size)) == 0) {
+ struct fsObject *o2 = *io_o;
+ u8 *name = o2->name;
+ u8 *objname = objectname;
+ struct buffer_head *node_bh;
+ struct fsObjectNode *on;
+ u32 nodeno;
+
+ **io_o = *src_o; /* Copying whole object data... */
+
+ while (*objname != 0) /* Copying name */
+ *name++ = *objname++;
+
+ *name++ = 0;
+ *name = 0; /* zero byte for comment */
+
+ if (o2->objectnode != 0) /* ObjectNode reuse or
creation */
+ errorcode = asfs_getnode(sb, o2->objectnode,
&node_bh, &on);
+ else {
+ if ((errorcode = asfs_createnode(sb, &node_bh,
(struct fsNode **) &on, &nodeno)) == 0) {
+ on->hash16 =
cpu_to_be16(asfs_hash(o2->name, ASFS_SB(sb)->flags &
ASFS_ROOTBITS_CASESENSITIVE));
+ o2->objectnode = cpu_to_be32(nodeno);
+ }
+ asfs_debug("createnode returned with
errorcode: %d\n", errorcode);
+ }
+
+ if (errorcode == 0) { /* in io_bh there is a
container with created object */
+ on->node.data = ((struct fsBlockHeader *)
(*io_bh)->b_data)->ownblock;
+ if ((errorcode = hashobject(sb, hashblock, on,
be32_to_cpu(o2->objectnode), objectname)) == 0) {
+ asfs_bstore(sb, node_bh);
+ asfs_brelse(node_bh);
+ } else
+ errorcode = -EIO;
+ }
+
+ if (errorcode == 0) { /* HashBlock reuse or creation:*/
+
+ if ((o2->bits & OTYPE_DIR) != 0 &&
o2->object.dir.hashtable == 0) {
+ struct buffer_head *hashbh;
+ u32 hashblock;
+
+ asfs_debug("creating Hashblock\n");
+
+ if ((errorcode =
asfs_allocadminspace(sb, &hashblock)) == 0 && (hashbh =
asfs_getzeroblk(sb, hashblock))) {
+ struct fsHashTable *ht = (void
*) hashbh->b_data;
+
+ o2->object.dir.hashtable =
cpu_to_be32(hashblock);
+
+ ht->bheader.id =
cpu_to_be32(ASFS_HASHTABLE_ID);
+ ht->bheader.ownblock =
cpu_to_be32(hashblock);
+ ht->parent = o2->objectnode;
+
+ asfs_bstore(sb, hashbh);
+ asfs_brelse(hashbh);
+ }
+ }
+ }
+
+ if (errorcode == 0) { /* SoftLink creation: */
+ if ((o2->bits & (OTYPE_LINK | OTYPE_HARDLINK))
== OTYPE_LINK && o2->object.file.data == 0) {
+ struct buffer_head *bh2;
+ u32 slinkblock;
+
+ if ((errorcode =
asfs_allocadminspace(sb, &slinkblock)) == 0 && (bh2 =
asfs_getzeroblk(sb, slinkblock))) {
+ struct fsSoftLink *sl = (void
*) bh2->b_data;
+ o2->object.file.data =
cpu_to_be32(slinkblock);
+ sl->bheader.id =
cpu_to_be32(ASFS_SOFTLINK_ID);
+ sl->bheader.ownblock =
cpu_to_be32(slinkblock);
+ sl->parent = o2->objectnode;
+ sl->next = 0;
+ sl->previous = 0;
+ asfs_bstore(sb, bh2);
+ asfs_brelse(bh2);
+ }
+ }
+ }
+ }
+ asfs_debug("createobject: done.\n");
+
+ return (errorcode);
+}
+
+ /* This function extends the file object 'o' with a number of blocks
+ (hopefully, if any blocks has been found!). Only new
Extents will
+ be created -- the size of the file will not be altered, and changing
+ it is left up to the caller. If the file did not have
any blocks
+ yet, then the o->object.file.data will be set to the
first (new)
+ ExtentBNode. It returns the number of added blocks through
+ addedblocks pointer */
+
+int asfs_addblockstofile(struct super_block *sb, struct buffer_head
*objbh, struct fsObject *o, u32 blocks, u32 * newspace, u32 *
addedblocks)
+{
+ u32 lastextentbnode;
+ int errorcode = 0;
+ struct fsExtentBNode *ebnp;
+ struct buffer_head *block = NULL;
+
+
+ asfs_debug("extendblocksinfile: Trying to increasing number of
blocks by %d.\n", blocks);
+
+ lastextentbnode = be32_to_cpu(o->object.file.data);
+
+ if (lastextentbnode != 0) {
+ while (lastextentbnode != 0 && errorcode == 0) {
+ if (block != NULL)
+ asfs_brelse(block);
+ errorcode = asfs_getextent(sb,
lastextentbnode, &block, &ebnp);
+ lastextentbnode = be32_to_cpu(ebnp->next);
+ }
+ lastextentbnode = be32_to_cpu(ebnp->key);
+ }
+
+ if (errorcode == 0) {
+ u32 searchstart;
+
+ u32 found_block;
+ u32 found_blocks;
+
+ *addedblocks = 0;
+ *newspace = 0;
+
+ if (lastextentbnode != 0)
+ searchstart = be32_to_cpu(ebnp->key) +
be16_to_cpu(ebnp->blocks);
+ else
+ searchstart = 0; //ASFS_SB(sb)->block_rovingblockptr;
+
+ if ((errorcode = asfs_findspace(sb, blocks,
searchstart, searchstart, &found_block, &found_blocks)) != 0) {
+ asfs_brelse(block);
+ asfs_debug("extendblocksinfile: findspace
returned %s\n", errorcode == -ENOSPC ? "ENOSPC" : "error");
+ return errorcode;
+ }
+
+ blocks = found_blocks;
+ errorcode = asfs_markspace(sb, found_block, found_blocks);
+ *addedblocks = found_blocks;
+ *newspace = found_block;
+
+ asfs_debug("extendblocksinfile: block = %u,
lastextentbnode = %u, extentblocks = %d\n", found_block,
lastextentbnode, blocks);
+
+ if ((errorcode = asfs_addblocks(sb, blocks,
found_block, be32_to_cpu(o->objectnode), &lastextentbnode)) != 0) {
+ asfs_debug("extendblocksinfile: addblocks
returned errorcode %d\n", errorcode);
+ return errorcode;
+ }
+
+ if (o->object.file.data == 0)
+ o->object.file.data = cpu_to_be32(lastextentbnode);
+ }
+
+ if (block)
+ asfs_brelse(block);
+ asfs_bstore(sb, objbh);
+
+ asfs_debug("addblockstofile: done. added %d blocks\n", *addedblocks);
+
+ return errorcode;
+}
+
+ /* The Object indicated by bh1 & o1, gets renamed to newname and placed
+ in the directory indicated by bhparent & oparent. */
+
+int asfs_renameobject(struct super_block *sb, struct buffer_head
*bh1, struct fsObject *o1, struct buffer_head *bhparent, struct
fsObject *oparent, u8 * newname)
+{
+ struct fsObject object;
+ u32 oldparentnode = be32_to_cpu(((struct fsObjectContainer *)
bh1->b_data)->parent);
+ u8 oldname[107];
+ int errorcode;
+
+ asfs_debug("renameobject: Renaming '%s' to '%s' in dir
'%s'\n", o1->name, newname, oparent->name);
+
+ object = *o1;
+ strcpy(oldname, o1->name);
+
+ if ((errorcode = dehashobjectquick(sb,
be32_to_cpu(o1->objectnode), o1->name, oldparentnode)) == 0) {
+ u32 parentobjectnode = be32_to_cpu(oparent->objectnode);
+
+ if ((errorcode = simpleremoveobject(sb, bh1, o1)) == 0) {
+ struct buffer_head *bh2 = bhparent;
+ struct fsObject *o2;
+
+ /* oparent might changed after simpleremoveobject */
+ oparent = o2 = find_obj_by_node(sb, (struct
fsObjectContainer *) bhparent->b_data, parentobjectnode);
+
+ /* In goes the Parent bh & o, out comes the
New object's bh & o :-) */
+ if ((errorcode = asfs_createobject(sb, &bh2,
&o2, &object, newname, TRUE)) == 0) {
+ asfs_bstore(sb, bh2);
+ if (be32_to_cpu(oparent->objectnode)
== ASFS_RECYCLEDNODE) {
+ asfs_debug("renameobject:
Updating recycled dir info\n");
+ if ((errorcode =
setrecycledinfodiff(sb, 1, (be32_to_cpu(o2->object.file.size) +
sb->s_blocksize - 1) >> sb->s_blocksize_bits)) != 0) {
+ brelse(bh2);
+ return errorcode;
+ }
+ }
+ brelse(bh2);
+ asfs_debug("renameobject: Succesfully
created & stored new object.\n");
+ } else { /* recreate object in old place,
maybe this will not fail, but who knows... */
+ asfs_debug("renameobject: Creating new
object failed. Trying to recreate it in source directory.\n");
+ if (asfs_readobject(sb, oldparentnode,
&bh1, &o1) == 0) {
+ struct buffer_head *bh2 = bh1;
+ if (asfs_createobject(sb,
&bh2, &o1, &object, oldname, TRUE) == 0) {
+ asfs_bstore(sb, bh2);
+ if (oldparentnode ==
ASFS_RECYCLEDNODE) {
+
asfs_debug("renameobject: Updating recycled dir info\n");
+
setrecycledinfodiff(sb, 1, (be32_to_cpu(o1->object.file.size) +
sb->s_blocksize - 1) >> sb->s_blocksize_bits);
+ }
+ brelse(bh2);
+ }
+ brelse(bh1);
+ }
+ }
+ }
+ }
+ return errorcode;
+}
+
+ /* Truncates the specified file to /newsize/ bytes */
+
+int asfs_truncateblocksinfile(struct super_block *sb, struct
buffer_head *bh, struct fsObject *o, u32 newsize)
+{
+ struct buffer_head *ebh;
+ struct fsExtentBNode *ebn;
+ int errorcode;
+ u32 pos = 0;
+ u32 newblocks = (newsize + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+ u32 filedata = be32_to_cpu(o->object.file.data);
+ u32 eprev, ekey;
+ u16 eblocks;
+
+ asfs_debug("trucateblocksinfile: newsize %u\n", newsize);
+
+ if (filedata == 0)
+ return 0;
+
+ for (;;) {
+ if ((errorcode = asfs_getextent(sb, filedata, &ebh, &ebn)) != 0)
+ return errorcode;
+ if (pos + be16_to_cpu(ebn->blocks) >= newblocks)
+ break;
+ pos += be16_to_cpu(ebn->blocks);
+ if ((filedata = be32_to_cpu(ebn->next)) == 0)
+ break;
+ asfs_brelse(ebh);
+ };
+
+ eblocks = newblocks - pos;
+ ekey = be32_to_cpu(ebn->key);
+ eprev = be32_to_cpu(ebn->prev);
+
+ if (be16_to_cpu(ebn->blocks) < eblocks) {
+ printk("ASFS: Extent chain is too short or damaged!\n");
+ asfs_brelse(ebh);
+ return -ENOENT;
+ }
+ if (be16_to_cpu(ebn->blocks) - eblocks > 0 && (errorcode =
asfs_freespace(sb, be32_to_cpu(ebn->key) + eblocks,
be16_to_cpu(ebn->blocks) - eblocks)) != 0) {
+ asfs_brelse(ebh);
+ return errorcode;
+ }
+ if (be32_to_cpu(ebn->next) > 0 && (errorcode =
asfs_deleteextents(sb, be32_to_cpu(ebn->next))) != 0) {
+ asfs_brelse(ebh);
+ return errorcode;
+ }
+ ebn->blocks = cpu_to_be16(eblocks);
+ ebn->next = 0;
+ asfs_bstore(sb, ebh);
+
+ if (eblocks == 0) {
+ if (eprev & MSB_MASK) {
+ o->object.file.data = 0;
+ asfs_bstore(sb, bh);
+ } else {
+ struct buffer_head *ebhp;
+ struct fsExtentBNode *ebnp;
+
+ if ((errorcode = asfs_getextent(sb, eprev &
!MSB_MASK, &ebhp, &ebnp)) != 0) {
+ asfs_brelse(ebh);
+ return errorcode;
+ }
+
+ ebnp->next = 0;
+ asfs_bstore(sb, ebhp);
+ asfs_brelse(ebhp);
+ }
+ if ((errorcode = asfs_deletebnode(sb, ebh, ekey)) != 0) {
+ asfs_brelse(ebh);
+ return errorcode;
+ }
+ }
+ asfs_brelse(ebh);
+
+ return 0;
+}
+#endif
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2009-02-12 8:05 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-12-26 12:07 [PATCH 7/9] Amiga SmartFileSystem Pavel Fedin
-- strict thread matches above, loose matches on Subject: below --
2009-02-09 6:56 Pavel Fedin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).