Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 33772 Details for
Bug 54684
Pegasos patches for gentoo-dev-sources
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
4725_asfs-1.0b6.patch
4725_asfs-1.0b6.patch (text/plain), 154.92 KB, created by
David Holm (RETIRED)
on 2004-06-21 13:38:27 UTC
(
hide
)
Description:
4725_asfs-1.0b6.patch
Filename:
MIME Type:
Creator:
David Holm (RETIRED)
Created:
2004-06-21 13:38:27 UTC
Size:
154.92 KB
patch
obsolete
>diff -urN kernel-source-2.6.5/Documentation/filesystems/00-INDEX kernel-source-2.6.5-powerpc/Documentation/filesystems/00-INDEX >--- kernel-source-2.6.5/Documentation/filesystems/00-INDEX 2002-10-19 06:02:35.000000000 +0200 >+++ kernel-source-2.6.5-powerpc/Documentation/filesystems/00-INDEX 2004-04-12 23:39:01.241890104 +0200 >@@ -6,6 +6,8 @@ > - info and mount options for the Acorn Advanced Disc Filing System. > affs.txt > - info and mount options for the Amiga Fast File System. >+asfs.txt >+ - info and mount options for the Amiga Smart File System. > bfs.txt > - info for the SCO UnixWare Boot Filesystem (BFS). > cifs.txt >diff -urN kernel-source-2.6.5/Documentation/filesystems/asfs.txt kernel-source-2.6.5-powerpc/Documentation/filesystems/asfs.txt >--- kernel-source-2.6.5/Documentation/filesystems/asfs.txt 1970-01-01 01:00:00.000000000 +0100 >+++ kernel-source-2.6.5-powerpc/Documentation/filesystems/asfs.txt 2004-04-12 23:39:01.243889800 +0200 >@@ -0,0 +1,150 @@ >+ >+Amiga SmartFileSystem, Linux implementation >+=========================================== >+ >+ASFS is a Amiga Smart FileSystem driver for Linux. It supports reading >+files and directories. From version 1.0 there is also an experimental >+(almost full) write support. Experimental means that it hasn't been >+tested enough yet, so use it with care. Symbolic links (in AmigaOS >+called soft links) are also supported read/write. Read notes below >+about symlinks support. >+ >+ >+Unsupported features of Amiga SFS >+================================ >+ >+ASFS currently does not support safe-delete feature of Amiga SFS >+filesystem. It simply deletes files instead of moving them to >+".recycled" directory. It also doesn't remove files from ".recycled" >+directory, when there is no space left on drive. >+ >+If there is no space left, you need to manually remove files from >+".recycled" directory. Also if you want to delete a file in a safe >+way, you need to move it to ".recycled" directory by hand. >+ >+Because of all of above, the amount of free space on disk does not >+include space used by all files from ".recycled" directory. >+ >+ >+Limitations >+=========== >+ >+There is no Amiga protection bits into Linux permission bits tranlation >+and vice versa. If you need this feature, mail me. >+ >+ASFS will always keep some amount of blocks free. This means that you >+cannot fill the drive completely. It is because Amiga SFS uses some >+special methods of writing data (called safe write), which needs some >+additional free space. >+ >+File systems with unfinished transactions (this happens when system crashed >+during writing data to disk on AmigaOS/MorphOS) will be mounted read-only >+to protect data. The only way to fix such filesystem is to mount it under >+AmigaOS or MorphOS. >+ >+Do not try to mount and write to filesystem with errors. Bad things will >+happen. >+ >+ >+Mount options for the ASFS >+========================== >+ >+setuid[=uid] >+ This sets the owner of all files and directories in the file >+ system to uid or the uid of the current user, respectively. >+ >+setgid[=gid] >+ Same as above, but for gid. >+ >+mode=mode >+ Sets the mode flags to the given (octal) value. Directories >+ will get an x permission if the corresponding r bit is set. >+ The default mode is 0666, which means all r and w bits are set >+ (for directories this means also that all x bits are set). >+ >+prefix=path >+ Path will be prefixed to every absolute path name of symbolic >+ links on an ASFS/AFFS partition. Default = "/". (See below.) >+ >+volume=name >+ When symbolic links with an absolute path are created >+ on an ASFS/AFFS partition, name will be prepended as the >+ volume name. Default = "" (empty string). (See below.) >+ >+lowercasevol >+ Translate all volume names in symlinks to lower case. >+ Disabled by default. (See below.) >+ >+Symbolic links >+============== >+ >+Although the Amiga and Linux file systems resemble each other, there >+are some, not always subtle, differences. One of them becomes apparent >+with symbolic links. While Linux has a file system with exactly one >+root directory, the Amiga has a separate root directory for each >+file system (for example, partition, floppy disk, ...). With the Amiga, >+these entities are called "volumes". They have symbolic names which >+can be used to access them. Thus, symbolic links can point to a >+different volume. ASFS turns the volume name into a directory name >+and prepends the prefix path (see prefix option) to it. When option >+"lowercasevol" is set, it also translates volume names to lower case. >+If the volume name is the same as a name given in "volume" option, >+it will be ignored and an absolute path will be created. >+ >+Example: >+You mount all your Amiga partitions under /amiga/<volume> (where >+<volume> is the name of the volume), and you give options >+`prefix="/amiga/",volume="Linux",lowercasevol' when mounting all your >+ASFS partitions. (They might be "User", "WB" and "Graphics", the mount >+points /amiga/user, /amiga/wb and /amiga/graphics). >+ >+A symbolic link referring to "USER:sc/include/dos/dos.h" will be >+translated to "/amiga/user/sc/include/dos/dos.h". >+A symbolic link referring to "Linux:etc/fstab" will be translated to >+"/etc/fstab". >+If you create a symlink referring to "/amiga/graphics/data/pict.jpg", >+it will be saved as "graphics:data/pict.jpg". >+If you create a symlink referring to "/boot/System.map", it will be >+saved as "Linux:boot/System.map". >+ >+ >+Other information >+================= >+ >+Supported block sizes are: 512, 1024, 2048 and 4096 bytes. Larger blocks >+speed up almost everything at the expense of wasted disk space. The speed >+gain above 4K seems not really worth the price, so you don't lose too >+much here, either. >+ >+This file system has been tested on Motorola PPC and 68k, as well as >+Intel x86 systems. I don't know, if it works on other Linux systems. >+ >+This filesystem is in BETA STAGE. This means that driver could crash in >+some circumstances and it also MIGHT corrupt/damage data on your disk. >+Remember! YOU USE IT ON YOUR OWN RISK! >+ >+I made almost all I could to minimalize this risk. On my systems several >+gigabytes has been succesfully copied from and to SFS disks. I would also >+appreciate any infomation if this filesystem works on your system or not. >+See next paragraph for my email. >+ >+Some parts of this documentation has been adapted from AFFS driver docs. >+ >+ >+Author, contact and copyright infos >+=================================== >+ >+ASFS has been written by Marek 'March' Szyprowski <marek@amiga.pl>. >+Mail me if you have any suggestions or found a bug. >+ >+Copyright (C) 2003,2004 Marek 'March' Szyprowski <marek@amiga.pl> >+ >+Thanks to Marcin Kurek (Morgoth/Dreamolers-CAPS) for help and parts >+of original amiga version of SmartFilesystem source code. >+ >+SmartFilesystem is copyrighted (C) 2003,2004 by: John Hendrikx, >+Ralph Schmidt, Emmanuel Lesueur, David Gerber and Marcin Kurek >+ >+The ASFS driver is realased under the terms of of the GNU General >+Public License. See source code for more details. >+ >diff -urN kernel-source-2.6.5/fs/asfs/adminspace.c kernel-source-2.6.5-powerpc/fs/asfs/adminspace.c >--- kernel-source-2.6.5/fs/asfs/adminspace.c 1970-01-01 01:00:00.000000000 +0100 >+++ kernel-source-2.6.5-powerpc/fs/asfs/adminspace.c 2004-04-12 23:39:01.000000000 +0200 >@@ -0,0 +1,445 @@ >+/* >+ * >+ * Amiga Smart File System, Linux implementation >+ * version: 1.0beta3 >+ * >+ * 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 <linux/asfs_fs.h> >+ >+#include <asm/byteorder.h> >+ >+#ifdef CONFIG_ASFS_RW >+ >+static int setfreeblocks(struct super_block *sb, u32 freeblocks) >+{ >+ 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)); >+ ASFS_SB(sb)->freeblocks = freeblocks; >+ ri->freeblocks = cpu_to_be32(freeblocks); >+ asfs_bstore(sb, bh); >+ asfs_brelse(bh); >+ return 0; >+ } >+ return -EIO; >+} >+ >+int enoughspace(struct super_block *sb, u32 blocks) >+{ >+ if (ASFS_SB(sb)->freeblocks - ASFS_ALWAYSFREE < blocks) >+ return FALSE; >+ >+ return TRUE; >+} >+ >+ /* Determines the amount of free blocks starting from block /block/. >+ If there are no blocks found or if there was an error -1 is returned, >+ otherwise this function will count the number of free blocks until >+ an allocated block is encountered or until maxneeded has been >+ exceeded. */ >+ >+int availablespace(struct super_block *sb, u32 block, u32 maxneeded) >+{ >+ struct buffer_head *bh = NULL; >+ struct fsBitmap *b; >+ u32 longs = ASFS_SB(sb)->blocks_inbitmap >> 5; >+ u32 maxbitmapblock = ASFS_SB(sb)->bitmapbase + ASFS_SB(sb)->blocks_bitmap; >+ int blocksfound = 0; >+ u32 bitstart; >+ int bitend; >+ u32 nextblock = ASFS_SB(sb)->bitmapbase + block / ASFS_SB(sb)->blocks_inbitmap; >+ >+ bitstart = block % ASFS_SB(sb)->blocks_inbitmap; >+ >+ while (nextblock < maxbitmapblock && (bh = asfs_breadcheck(sb, nextblock++, ASFS_BITMAP_ID))) { >+ b = (void *) bh->b_data; >+ >+ if ((bitend = bmffz(b->bitmap, longs, bitstart)) >= 0) { >+ blocksfound += bitend - bitstart; >+ asfs_brelse(bh); >+ return blocksfound; >+ } >+ blocksfound += ASFS_SB(sb)->blocks_inbitmap - bitstart; >+ if (blocksfound >= maxneeded) { >+ asfs_brelse(bh); >+ return blocksfound; >+ } >+ bitstart = 0; >+ asfs_brelse(bh); >+ } >+ >+ if (bh == NULL) >+ return (-1); >+ >+ return (blocksfound); >+} >+ >+int findspace(struct super_block *sb, u32 maxneeded, u32 start, u32 end, u32 * returned_block, u32 * returned_blocks) >+{ >+ struct buffer_head *bh; >+ u32 longs = ASFS_SB(sb)->blocks_inbitmap >> 5; >+ u32 space = 0; >+ u32 block; >+ u32 bitmapblock = ASFS_SB(sb)->bitmapbase + start / ASFS_SB(sb)->blocks_inbitmap; >+ u32 breakpoint; >+ int bitstart, bitend; >+ int reads; >+ >+ if (enoughspace(sb, maxneeded) == FALSE) { >+ *returned_block = 0; >+ *returned_blocks = 0; >+ return -ENOSPC; >+ } >+ >+ if (start >= ASFS_SB(sb)->totalblocks) >+ start -= ASFS_SB(sb)->totalblocks; >+ >+ if (end == 0) >+ end = ASFS_SB(sb)->totalblocks; >+ >+ reads = ((end - 1) / ASFS_SB(sb)->blocks_inbitmap) + 1 - start / ASFS_SB(sb)->blocks_inbitmap; >+ >+ if (start >= end) >+ reads += (ASFS_SB(sb)->totalblocks - 1) / ASFS_SB(sb)->blocks_inbitmap + 1; >+ >+ breakpoint = (start < end ? end : ASFS_SB(sb)->totalblocks); >+ >+ *returned_block = 0; >+ *returned_blocks = 0; >+ >+ bitend = start % ASFS_SB(sb)->blocks_inbitmap; >+ block = start - bitend; >+ >+ while ((bh = asfs_breadcheck(sb, bitmapblock++, ASFS_BITMAP_ID))) { >+ struct fsBitmap *b = (void *) bh->b_data; >+ u32 localbreakpoint = breakpoint - block; >+ >+ if (localbreakpoint > ASFS_SB(sb)->blocks_inbitmap) >+ localbreakpoint = ASFS_SB(sb)->blocks_inbitmap; >+ >+ /* At this point space contains the amount of free blocks at >+ the end of the previous bitmap block. If there are no >+ free blocks at the start of this bitmap block, space will >+ be set to zero, since in that case the space isn't adjacent. */ >+ >+ while ((bitstart = bmffo(b->bitmap, longs, bitend)) < ASFS_SB(sb)->blocks_inbitmap) { >+ /* found the start of an empty space, now find out how large it is */ >+ >+ if (bitstart >= localbreakpoint) >+ break; >+ >+ if (bitstart != 0) >+ space = 0; >+ >+ bitend = bmffz(b->bitmap, longs, bitstart); >+ >+ if (bitend > localbreakpoint) >+ bitend = localbreakpoint; >+ >+ space += bitend - bitstart; >+ >+ if (*returned_blocks < space) { >+ *returned_block = block + bitend - space; >+ if (space >= maxneeded) { >+ *returned_blocks = maxneeded; >+ asfs_brelse(bh); >+ return 0; >+ } >+ *returned_blocks = space; >+ } >+ >+ if (bitend >= localbreakpoint) >+ break; >+ } >+ >+ if (--reads == 0) >+ break; >+ >+ /* no (more) empty spaces found in this block */ >+ >+ if (bitend != ASFS_SB(sb)->blocks_inbitmap) >+ space = 0; >+ >+ bitend = 0; >+ block += ASFS_SB(sb)->blocks_inbitmap; >+ >+ if (block >= ASFS_SB(sb)->totalblocks) { >+ block = 0; >+ space = 0; >+ breakpoint = end; >+ bitmapblock = ASFS_SB(sb)->bitmapbase; >+ } >+ asfs_brelse(bh); >+ } >+ >+ if (bh == NULL) >+ return -EIO; >+ >+ asfs_brelse(bh); >+ >+ if (*returned_blocks == 0) >+ return -ENOSPC; >+ else >+ return 0; >+} >+ >+int markspace(struct super_block *sb, u32 block, u32 blocks) >+{ >+ int errorcode; >+ >+ asfs_debug("markspace: Marking %d blocks from block %d\n", blocks, block); >+ >+ if ((availablespace(sb, block, blocks)) < blocks) { >+ printk("ASFS: Attempted to mark %d blocks from block %d, but some of them were already full!\n", blocks, block); >+ return -EIO; >+ } >+ >+ if ((errorcode = setfreeblocks(sb, ASFS_SB(sb)->freeblocks - blocks)) == 0) { >+ struct buffer_head *bh; >+ u32 skipblocks = block / ASFS_SB(sb)->blocks_inbitmap; >+ u32 longs = (sb->s_blocksize - sizeof(struct fsBitmap)) >> 2; >+ u32 bitmapblock; >+ >+ block -= skipblocks * ASFS_SB(sb)->blocks_inbitmap; >+ bitmapblock = ASFS_SB(sb)->bitmapbase + skipblocks; >+ >+ while (blocks > 0) { >+ if ((bh = asfs_breadcheck(sb, bitmapblock++, ASFS_BITMAP_ID))) { >+ struct fsBitmap *b = (void *) bh->b_data; >+ >+ blocks -= bmclr(b->bitmap, longs, block, blocks); >+ block = 0; >+ >+ asfs_bstore(sb, bh); >+ asfs_brelse(bh); >+ } else >+ return -EIO; >+ } >+ } >+ >+ return (errorcode); >+} >+ >+ /* This function checks the bitmap and tries to locate at least /blocksneeded/ >+ adjacent unused blocks. If found it sets returned_block to the start block >+ and returns no error. If not found, ERROR_DISK_IS_FULL is returned and >+ returned_block is set to zero. Any other errors are returned as well. */ >+ >+static inline int internalfindspace(struct super_block *sb, u32 blocksneeded, u32 startblock, u32 endblock, u32 * returned_block) >+{ >+ u32 blocks; >+ int errorcode; >+ >+ if ((errorcode = findspace(sb, blocksneeded, startblock, endblock, returned_block, &blocks)) == 0) >+ if (blocks != blocksneeded) >+ return -ENOSPC; >+ >+ return errorcode; >+} >+ >+static int findandmarkspace(struct super_block *sb, u32 blocksneeded, u32 * returned_block) >+{ >+ int errorcode; >+ >+ if (enoughspace(sb, blocksneeded) != FALSE) { >+ if ((errorcode = internalfindspace(sb, blocksneeded, 0, ASFS_SB(sb)->totalblocks, returned_block)) == 0) >+ errorcode = markspace(sb, *returned_block, blocksneeded); >+ } else >+ errorcode = -ENOSPC; >+ >+ return (errorcode); >+} >+ >+/* ************************** */ >+ >+int freespace(struct super_block *sb, u32 block, u32 blocks) >+{ >+ int errorcode; >+ >+ asfs_debug("freespace: Freeing %d blocks from block %d\n", blocks, block); >+ >+ if ((errorcode = setfreeblocks(sb, ASFS_SB(sb)->freeblocks + blocks)) == 0) { >+ struct buffer_head *bh; >+ u32 skipblocks = block / ASFS_SB(sb)->blocks_inbitmap; >+ u32 longs = (sb->s_blocksize - sizeof(struct fsBitmap)) >> 2; >+ u32 bitmapblock; >+ >+ block -= skipblocks * ASFS_SB(sb)->blocks_inbitmap; >+ bitmapblock = ASFS_SB(sb)->bitmapbase + skipblocks; >+ >+ while (blocks > 0) { >+ if ((bh = asfs_breadcheck(sb, bitmapblock++, ASFS_BITMAP_ID))) { >+ struct fsBitmap *b = (void *) bh->b_data; >+ >+ blocks -= bmset(b->bitmap, longs, block, blocks); >+ block = 0; >+ >+ asfs_bstore(sb, bh); >+ asfs_brelse(bh); >+ } else >+ return -EIO; >+ } >+ } >+ >+ return (errorcode); >+} >+ >+/*************** admin space containers ****************/ >+ >+int allocadminspace(struct super_block *sb, u32 *returned_block) >+{ >+ struct buffer_head *bh; >+ u32 adminspaceblock = ASFS_SB(sb)->adminspacecontainer; >+ int errorcode = -EIO; >+ >+ asfs_debug("allocadminspace: allocating new block\n"); >+ >+ while ((bh = asfs_breadcheck(sb, adminspaceblock, ASFS_ADMINSPACECONTAINER_ID))) { >+ struct fsAdminSpaceContainer *asc1 = (void *) bh->b_data; >+ struct fsAdminSpace *as1 = asc1->adminspace; >+ int adminspaces1 = (sb->s_blocksize - sizeof(struct fsAdminSpaceContainer)) / sizeof(struct fsAdminSpace); >+ >+ while (adminspaces1-- > 0) { >+ s16 bitoffset; >+ >+ if (as1->space != 0 && (bitoffset = bfffz(be32_to_cpu(as1->bits), 0)) >= 0) { >+ u32 emptyadminblock = be32_to_cpu(as1->space) + bitoffset; >+ as1->bits |= cpu_to_be32(1 << (31 - bitoffset)); >+ asfs_bstore(sb, bh); >+ *returned_block = emptyadminblock; >+ asfs_brelse(bh); >+ asfs_debug("allocadminspace: found block %d\n", *returned_block); >+ return 0; >+ } >+ as1++; >+ } >+ >+ adminspaceblock = be32_to_cpu(asc1->next); >+ asfs_brelse(bh); >+ >+ if (adminspaceblock == 0) { >+ u32 startblock; >+ >+ asfs_debug("allocadminspace: allocating new adminspace area\n"); >+ >+ /* If we get here it means current adminspace areas are all filled. >+ We would now need to find a new area and create a fsAdminSpace >+ structure in one of the AdminSpaceContainer blocks. If these >+ don't have any room left for new adminspace areas a new >+ AdminSpaceContainer would have to be created first which is >+ placed as the first block in the newly found admin area. */ >+ >+ adminspaceblock = ASFS_SB(sb)->adminspacecontainer; >+ >+ if ((errorcode = findandmarkspace(sb, 32, &startblock))) >+ return errorcode; >+ >+ while ((bh = asfs_breadcheck(sb, adminspaceblock, ASFS_ADMINSPACECONTAINER_ID))) { >+ struct fsAdminSpaceContainer *asc2 = (void *) bh->b_data; >+ struct fsAdminSpace *as2 = asc2->adminspace; >+ int adminspaces2 = (sb->s_blocksize - sizeof(struct fsAdminSpaceContainer)) / sizeof(struct fsAdminSpace); >+ >+ while (adminspaces2-- > 0 && as2->space != 0) >+ as2++; >+ >+ if (adminspaces2 >= 0) { /* Found a unused AdminSpace in this AdminSpaceContainer! */ >+ as2->space = cpu_to_be32(startblock); >+ as2->bits = 0; >+ asfs_bstore(sb, bh); >+ asfs_brelse(bh); >+ break; >+ } >+ >+ if (asc2->next == 0) { >+ /* Oh-oh... we marked our new adminspace area in use, but we couldn't >+ find space to store a fsAdminSpace structure in the existing >+ fsAdminSpaceContainer blocks. This means we need to create and >+ link a new fsAdminSpaceContainer as the first block in our newly >+ marked adminspace. */ >+ >+ asc2->next = cpu_to_be32(startblock); >+ asfs_bstore(sb, bh); >+ asfs_brelse(bh); >+ >+ /* Now preparing new AdminSpaceContainer */ >+ >+ if ((bh = asfs_getzeroblk(sb, startblock)) == NULL) >+ return -EIO; >+ >+ asc2 = (void *) bh->b_data; >+ asc2->bheader.id = cpu_to_be32(ASFS_ADMINSPACECONTAINER_ID); >+ asc2->bheader.ownblock = cpu_to_be32(startblock); >+ asc2->previous = cpu_to_be32(adminspaceblock); >+ asc2->adminspace[0].space = cpu_to_be32(startblock); >+ asc2->adminspace[0].bits = cpu_to_be32(0x80000000); >+ asc2->bits = 32; >+ >+ asfs_bstore(sb, bh); >+ asfs_brelse(bh); >+ >+ adminspaceblock = startblock; >+ break; /* Breaks through to outer loop! */ >+ } >+ adminspaceblock = be32_to_cpu(asc2->next); >+ asfs_brelse(bh); >+ } >+ } >+ } >+ return errorcode; >+} >+ >+int freeadminspace(struct super_block *sb, u32 block) >+{ >+ struct buffer_head *bh; >+ u32 adminspaceblock = ASFS_SB(sb)->adminspacecontainer; >+ >+ asfs_debug("freeadminspace: Entry -- freeing block %d\n", block); >+ >+ while ((bh = asfs_breadcheck(sb, adminspaceblock, ASFS_ADMINSPACECONTAINER_ID))) { >+ struct fsAdminSpaceContainer *asc = (void *) bh->b_data; >+ struct fsAdminSpace *as = asc->adminspace; >+ int adminspaces = (sb->s_blocksize - sizeof(struct fsAdminSpaceContainer)) / sizeof(struct fsAdminSpace); >+ >+ while (adminspaces-- > 0) { >+ if (block >= be32_to_cpu(as->space) && block < be32_to_cpu(as->space) + 32) { >+ s16 bitoffset = block - be32_to_cpu(as->space); >+ asfs_debug("freeadminspace: Block to be freed is located in AdminSpaceContainer block at %d\n", adminspaceblock); >+ as->bits &= cpu_to_be32(~(1 << (31 - bitoffset))); >+ asfs_bstore(sb, bh); >+ asfs_brelse(bh); >+ return 0; >+ } >+ as++; >+ } >+ >+ if ((adminspaceblock = be32_to_cpu(asc->next)) == 0) >+ break; >+ >+ asfs_brelse(bh); >+ } >+ >+ if (bh != NULL) { >+ asfs_brelse(bh); >+ printk("ASFS: Unable to free an administration block. The block cannot be found."); >+ return -ENOENT; >+ } >+ >+ return -EIO; >+} >+ >+#endif >diff -urN kernel-source-2.6.5/fs/asfs/bitfuncs.c kernel-source-2.6.5-powerpc/fs/asfs/bitfuncs.c >--- kernel-source-2.6.5/fs/asfs/bitfuncs.c 1970-01-01 01:00:00.000000000 +0100 >+++ kernel-source-2.6.5-powerpc/fs/asfs/bitfuncs.c 2004-04-12 23:39:01.000000000 +0200 >@@ -0,0 +1,249 @@ >+/* >+ * >+ * 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 <asm/byteorder.h> >+ >+#ifdef CONFIG_ASFS_RW >+ >+static s16 bfffo(u32 data, s16 bitoffset) >+{ >+ u32 bitmask = 1 << (31 - bitoffset); >+ >+ /** Finds first set bit in /data/ starting at /bitoffset/. This function >+ considers the MSB to be the first bit. */ >+ >+ do { >+ if ((data & bitmask) != 0) { >+ return bitoffset; >+ } >+ bitoffset++; >+ bitmask >>= 1; >+ } while (bitmask != 0); >+ >+ return -1; >+} >+ >+ >+s16 bfffz(u32 data, s16 bitoffset) >+{ >+ u32 bitmask = 1 << (31 - bitoffset); >+ >+ /** Finds first zero bit in /data/ starting at /bitoffset/. This function >+ considers the MSB to be the first bit. */ >+ >+ do { >+ if ((data & bitmask) == 0) { >+ return (bitoffset); >+ } >+ bitoffset++; >+ bitmask >>= 1; >+ } while (bitmask != 0); >+ >+ return (-1); >+} >+ >+ >+ >+static u32 bfset(u32 data, s16 bitoffset, s16 bits) >+{ >+ u32 mask; >+ >+ /** Sets /bits/ bits starting from /bitoffset/ in /data/. >+ /bits/ must be between 1 and 32. */ >+ >+ /* we want a mask which sets /bits/ bits starting from bit 31 */ >+ >+ mask = ~((1 << (32 - bits)) - 1); >+ mask >>= bitoffset; >+ >+ return data | mask; >+} >+ >+ >+static u32 bfclr(u32 data, s16 bitoffset, s16 bits) >+{ >+ u32 mask; >+ >+ /* we want a mask which sets /bits/ bits starting from bit 31 */ >+ >+ mask = ~((1 << (32 - bits)) - 1); >+ mask >>= bitoffset; >+ >+ return data & ~mask; >+} >+ >+ >+/* bitmap (bm) functions: >+ >+ These functions perform bit-operations on regions of memory which >+ are a multiple of 4 bytes in length. Bitmap is in bigendian byte order. >+*/ >+ >+s32 bmffo(u32 * bitmap, s32 longs, s32 bitoffset) >+{ >+ u32 *scan = bitmap; >+ u32 longoffset; >+ s16 bit; >+ >+ /* This function finds the first set bit in a region of memory starting >+ with /bitoffset/. The region of memory is /longs/ longs long. It >+ returns the bitoffset of the first set bit it finds. */ >+ >+ longoffset = bitoffset >> 5; >+ longs -= longoffset; >+ scan += longoffset; >+ >+ bitoffset = bitoffset & 0x1F; >+ >+ if (bitoffset != 0) { >+ if ((bit = bfffo(be32_to_cpu(*scan), bitoffset)) >= 0) { >+ return (bit + ((scan - bitmap) << 5)); >+ } >+ >+ scan++; >+ longs--; >+ } >+ >+ while (longs-- > 0) { >+ if (*scan++ != 0) { >+ return (bfffo(be32_to_cpu(*--scan), 0) + ((scan - bitmap) << 5)); >+ } >+ } >+ >+ return (-1); >+} >+ >+s32 bmffz(u32 * bitmap, s32 longs, s32 bitoffset) >+{ >+ u32 *scan = bitmap; >+ u32 longoffset; >+ s16 bit; >+ >+ /* This function finds the first unset bit in a region of memory starting >+ with /bitoffset/. The region of memory is /longs/ longs long. It >+ returns the bitoffset of the first unset bit it finds. */ >+ >+ longoffset = bitoffset >> 5; >+ longs -= longoffset; >+ scan += longoffset; >+ >+ bitoffset = bitoffset & 0x1F; >+ >+ if (bitoffset != 0) { >+ if ((bit = bfffz(be32_to_cpu(*scan), bitoffset)) >= 0) { >+ return (bit + ((scan - bitmap) << 5)); >+ } >+ >+ scan++; >+ longs--; >+ } >+ >+ while (longs-- > 0) { >+ if (*scan++ != 0xFFFFFFFF) { >+ return (bfffz(be32_to_cpu(*--scan), 0) + ((scan - bitmap) << 5)); >+ } >+ } >+ >+ return (-1); >+} >+ >+s32 bmclr(u32 * bitmap, s32 longs, s32 bitoffset, s32 bits) >+{ >+ u32 *scan = bitmap; >+ u32 longoffset; >+ s32 orgbits = bits; >+ >+ /* This function clears /bits/ bits in a region of memory starting >+ with /bitoffset/. The region of memory is /longs/ longs long. If >+ the region of memory is too small to clear /bits/ bits then this >+ function exits after having cleared all bits till the end of the >+ memory region. In any case it returns the number of bits which >+ were actually cleared. */ >+ >+ longoffset = bitoffset >> 5; >+ longs -= longoffset; >+ scan += longoffset; >+ >+ bitoffset = bitoffset & 0x1F; >+ >+ if (bitoffset != 0) { >+ if (bits < 32) { >+ *scan = cpu_to_be32(bfclr(be32_to_cpu(*scan), bitoffset, bits)); >+ } else { >+ *scan = cpu_to_be32(bfclr(be32_to_cpu(*scan), bitoffset, 32)); >+ } >+ >+ scan++; >+ longs--; >+ bits -= 32 - bitoffset; >+ } >+ >+ while (bits > 0 && longs-- > 0) { >+ if (bits > 31) { >+ *scan++ = 0; >+ } else { >+ *scan = cpu_to_be32(bfclr(be32_to_cpu(*scan), 0, bits)); >+ } >+ bits -= 32; >+ } >+ >+ if (bits <= 0) { >+ return (orgbits); >+ } >+ return (orgbits - bits); >+} >+ >+s32 bmset(u32 * bitmap, s32 longs, s32 bitoffset, s32 bits) >+{ >+ u32 *scan = bitmap; >+ u32 longoffset; >+ s32 orgbits = bits; >+ >+ /* This function sets /bits/ bits in a region of memory starting >+ with /bitoffset/. The region of memory is /longs/ longs long. If >+ the region of memory is too small to set /bits/ bits then this >+ function exits after having set all bits till the end of the >+ memory region. In any case it returns the number of bits which >+ were actually set. */ >+ >+ longoffset = bitoffset >> 5; >+ longs -= longoffset; >+ scan += longoffset; >+ >+ bitoffset = bitoffset & 0x1F; >+ >+ if (bitoffset != 0) { >+ if (bits < 32) { >+ *scan = cpu_to_be32(bfset(be32_to_cpu(*scan), bitoffset, bits)); >+ } else { >+ *scan = cpu_to_be32(bfset(be32_to_cpu(*scan), bitoffset, 32)); >+ } >+ >+ scan++; >+ longs--; >+ bits -= 32 - bitoffset; >+ } >+ >+ while (bits > 0 && longs-- > 0) { >+ if (bits > 31) { >+ *scan++ = 0xFFFFFFFF; >+ } else { >+ *scan = cpu_to_be32(bfset(be32_to_cpu(*scan), 0, bits)); >+ } >+ bits -= 32; >+ } >+ >+ if (bits <= 0) { >+ return (orgbits); >+ } >+ return (orgbits - bits); >+} >+ >+#endif >diff -urN kernel-source-2.6.5/fs/asfs/dir.c kernel-source-2.6.5-powerpc/fs/asfs/dir.c >--- kernel-source-2.6.5/fs/asfs/dir.c 1970-01-01 01:00:00.000000000 +0100 >+++ kernel-source-2.6.5-powerpc/fs/asfs/dir.c 2004-04-12 23:39:01.000000000 +0200 >@@ -0,0 +1,221 @@ >+/* >+ * >+ * Amiga Smart File System, Linux implementation >+ * version: 1.0beta3 >+ * >+ * Copyright (C) 2003,2004 Marek 'March' Szyprowski <marek@amiga.pl> >+ * >+ * >+ * 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/asfs_fs.h> >+#include <linux/fs.h> >+#include <linux/buffer_head.h> >+#include <linux/vfs.h> >+ >+#include <asm/byteorder.h> >+ >+extern struct dentry_operations asfs_dentry_operations; >+ >+int asfs_readdir(struct file *filp, void *dirent, filldir_t filldir) >+{ >+ struct inode *dir = filp->f_dentry->d_inode; >+ struct super_block *sb = dir->i_sb; >+ unsigned long f_pos; >+ int stored = 0; >+ >+ struct buffer_head *bh; >+ struct fsObjectContainer *objcont; >+ struct fsObject *obj; >+ u32 block; >+ int startnode; >+ int add; >+ >+ asfs_debug("asfs_readdir:\n"); >+ >+ if (filp->f_pos == ASFS_SB(sb)->totalblocks) >+ return stored; >+ >+ f_pos = filp->f_pos; >+ >+ if (f_pos == 0) { >+ filp->private_data = (void *)0; >+ if (filldir(dirent, ".", 1, f_pos, dir->i_ino, DT_DIR) < 0) >+ return 0; >+ filp->f_pos = f_pos = 1; >+ stored++; >+ } >+ if (f_pos == 1) { >+ if (filldir(dirent, "..", 2, f_pos, parent_ino(filp->f_dentry), DT_DIR) < 0) >+ return stored; >+ filp->f_pos = f_pos = 2; >+ stored++; >+ } >+ >+ if (ASFS_I(dir)->firstblock == 0) { /* empty directory */ >+ filp->f_pos = ASFS_SB(sb)->totalblocks; >+ ASFS_I(dir)->modified = 0; >+ return stored; >+ } >+ >+ if (f_pos == 2) { /* reading directory from its beginning */ >+ block = ASFS_I(dir)->firstblock; >+ add = 1; >+ startnode = 0; >+ } else { >+ startnode = (int)filp->private_data; >+ add = 0; >+ if (ASFS_I(dir)->modified == 0) >+ block = f_pos; >+ else >+ block = ASFS_I(dir)->firstblock; >+ } >+ >+ do { >+ if (!(bh = asfs_breadcheck(sb, block, ASFS_OBJECTCONTAINER_ID))) >+ return stored; >+ objcont = (struct fsObjectContainer *) bh->b_data; >+ obj = &(objcont->object[0]); >+ >+ while (be32_to_cpu(obj->objectnode) > 0 && >+ ((char *)obj - (char *)objcont) + sizeof(struct fsObject) + 2 < sb->s_blocksize) { >+ >+ if (!add && be32_to_cpu(obj->objectnode) == startnode) >+ add++; >+ >+ if (add && !(obj->bits & OTYPE_HIDDEN)) { >+ unsigned int type; >+ asfs_debug("ASFS: DirFilling: entry #%d \"%s\" (node %u offset %u), type %x\n", \ >+ stored, obj->name, be32_to_cpu(obj->objectnode), block, obj->bits); >+ filp->f_pos = block; >+ >+ if (obj->bits & OTYPE_DIR) >+ type = DT_DIR; >+ else if (obj->bits & OTYPE_LINK && !(obj->bits & OTYPE_HARDLINK)) >+ type = DT_LNK; >+ else >+ type = DT_REG; >+ >+ if (filldir(dirent, obj->name, strlen(obj->name), block, be32_to_cpu(obj->objectnode), type) < 0) { >+ filp->private_data = (void *)be32_to_cpu(obj->objectnode); >+ ASFS_I(dir)->modified = 0; >+ asfs_debug("ASFS: DirFilling: to be continued...\n"); >+ asfs_brelse(bh); >+ return stored; >+ } >+ stored++; >+ } >+ obj = asfs_nextobject(obj); >+ } >+ block = be32_to_cpu(objcont->next); >+ asfs_brelse(bh); >+ >+ } while (block != 0); >+ >+ filp->f_pos = ASFS_SB(sb)->totalblocks; >+ ASFS_I(dir)->modified = 0; >+ >+ return stored; >+} >+ >+struct dentry *asfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) >+{ >+ int res = -EACCES; /* placeholder for "no data here" */ >+ struct inode *inode; >+ struct super_block *sb = dir->i_sb; >+ u8 *name = (u8 *) dentry->d_name.name; >+ struct buffer_head *bh; >+ struct fsObject *obj; >+ >+ asfs_debug("asfs_lookup: (searching \"%s\"...) ", name); >+ >+ lock_super(sb); >+ >+ if (ASFS_I(dir)->hashtable != 0) { /* hashtable block is available, quick search */ >+ struct fsObjectNode *node_p; >+ struct buffer_head *node_bh; >+ u32 node; >+ u16 hash16; >+ >+ asfs_debug("(quick search) "); >+ >+ if (!(bh = asfs_breadcheck(sb, ASFS_I(dir)->hashtable, ASFS_HASHTABLE_ID))) { >+ unlock_super(sb); >+ return ERR_PTR(res); >+ } >+ hash16 = asfs_hash(name, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE); >+ node = be32_to_cpu(((struct fsHashTable *) bh->b_data)->hashentry[HASHCHAIN(hash16)]); >+ asfs_brelse(bh); >+ >+ while (node != 0) { >+ if (getnode(sb, node, &node_bh, &node_p) != 0) >+ goto not_found; >+ if (be16_to_cpu(node_p->hash16) == hash16) { >+ if (!(bh = asfs_breadcheck(sb, be32_to_cpu(node_p->node.data), ASFS_OBJECTCONTAINER_ID))) { >+ asfs_brelse(node_bh); >+ unlock_super(sb); >+ return ERR_PTR(res); >+ } >+ if ((obj = find_obj_by_name(sb, (struct fsObjectContainer *) bh->b_data, name)) != NULL) { >+ asfs_brelse(node_bh); >+ goto found_inode; >+ } >+ asfs_brelse(bh); >+ } >+ node = be32_to_cpu(node_p->next); >+ asfs_brelse(node_bh); >+ } >+ } else { /* hashtable not available, long search */ >+ struct fsObjectContainer *objcont; >+ u32 block; >+ >+ asfs_debug("(long search) "); >+ >+ block = ASFS_I(dir)->firstblock; >+ >+ if (block == 0) >+ goto not_found; >+ do { >+ if (!(bh = asfs_breadcheck(sb, block, ASFS_OBJECTCONTAINER_ID))) { >+ unlock_super(sb); >+ return ERR_PTR(res); >+ } >+ objcont = (struct fsObjectContainer *) bh->b_data; >+ if ((obj = find_obj_by_name(sb, objcont, name)) != NULL) >+ goto found_inode; >+ block = be32_to_cpu(objcont->next); >+ asfs_brelse(bh); >+ } while (block != 0); >+ } >+ >+not_found: >+ unlock_super(sb); >+ inode = NULL; >+ asfs_debug("object not found.\n"); >+ if (0) { >+found_inode: >+ unlock_super(sb); >+ if (!(inode = iget_locked(sb, be32_to_cpu(obj->objectnode)))) { >+ asfs_debug("ASFS: Strange - no inode allocated.\n"); >+ return ERR_PTR(res); >+ } >+ if (inode->i_state & I_NEW) { >+ asfs_read_locked_inode(inode, obj); >+ unlock_new_inode(inode); >+ } >+ >+ asfs_brelse(bh); >+ } >+ res = 0; >+ dentry->d_op = &asfs_dentry_operations; >+ d_add(dentry, inode); >+ return ERR_PTR(res); >+} >diff -urN kernel-source-2.6.5/fs/asfs/extents.c kernel-source-2.6.5-powerpc/fs/asfs/extents.c >--- kernel-source-2.6.5/fs/asfs/extents.c 1970-01-01 01:00:00.000000000 +0100 >+++ kernel-source-2.6.5-powerpc/fs/asfs/extents.c 2004-04-12 23:39:01.000000000 +0200 >@@ -0,0 +1,585 @@ >+/* >+ * >+ * Amiga Smart File System, Linux implementation >+ * version: 1.0beta3 >+ * >+ * 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/asfs_fs.h> >+#include <linux/fs.h> >+#include <linux/buffer_head.h> >+#include <linux/vfs.h> >+ >+#include <asm/byteorder.h> >+ >+ /* This function looks for the BNode equal to the key. If no >+ exact match is available then the BNode which is slightly >+ lower than key will be returned. If no such BNode exists >+ either, then the first BNode in this block is returned. >+ >+ This function will return the first BNode even if there >+ are no BNode's at all in this block (this can only happen >+ for the Root of the tree). Be sure to check if the Root >+ is not empty before calling this function. */ >+ >+static struct BNode *searchforbnode(u32 key, struct BTreeContainer *tc) >+{ >+ struct BNode *tn; >+ s16 n = be16_to_cpu(tc->nodecount) - 1; >+ >+ tn = (struct BNode *) ((u8 *) tc->bnode + n * tc->nodesize); >+ for (;;) { >+ if (n <= 0 || key >= be32_to_cpu(tn->key)) >+ return tn; >+ >+ tn = (struct BNode *) ((u8 *) tn - tc->nodesize); >+ n--; >+ } >+} >+ >+/* This function finds the BNode with the given key. If no exact match can be >+ found then this function will return either the next or previous closest >+ match (don't rely on this). >+ >+ If there were no BNode's at all, then *returned_bh will be NULL. */ >+ >+static int findbnode(struct super_block *sb, u32 key, struct buffer_head **returned_bh, struct BNode **returned_bnode) >+{ >+ u32 rootblock = ASFS_SB(sb)->extentbnoderoot; >+ >+ asfs_debug("findbnode: Looking for BNode with key %d\n", key); >+ >+ while ((*returned_bh = asfs_breadcheck(sb, rootblock, ASFS_BNODECONTAINER_ID))) { >+ struct fsBNodeContainer *bnc = (void *) (*returned_bh)->b_data; >+ struct BTreeContainer *btc = &bnc->btc; >+ >+ if (btc->nodecount == 0) { >+ *returned_bnode = NULL; >+ break; >+ } >+ >+ *returned_bnode = searchforbnode(key, btc); >+ if (btc->isleaf == TRUE) >+ break; >+ >+ rootblock = be32_to_cpu((*returned_bnode)->data); >+ asfs_brelse(*returned_bh); >+ } >+ >+ if (*returned_bh == NULL) >+ return -EIO; >+ >+ return 0; >+} >+ >+int getextent(struct super_block *sb, u32 key, struct buffer_head **ret_bh, struct fsExtentBNode **ret_ebn) >+{ >+ int result; >+ if ((result = findbnode(sb, key, ret_bh, (struct BNode **)ret_ebn)) == 0) >+ if (be32_to_cpu((*ret_ebn)->key) != key) { >+ brelse(*ret_bh); >+ *ret_bh = NULL; >+ return -ENOENT; >+ } >+ >+ return result; >+} >+ >+#ifdef CONFIG_ASFS_RW >+ >+ /* This routine inserts a node sorted into a BTreeContainer. It does >+ this by starting at the end, and moving the nodes one by one to >+ a higher slot until the empty slot has the correct position for >+ this key. Donot use this function on completely filled >+ BTreeContainers! */ >+ >+static struct BNode *insertbnode(u32 key, struct BTreeContainer *btc) >+{ >+ struct BNode *bn; >+ bn = (struct BNode *) ((u8 *) btc->bnode + btc->nodesize * (be16_to_cpu(btc->nodecount) - 1)); >+ >+ for (;;) { >+ if (bn < btc->bnode || key > be32_to_cpu(bn->key)) { >+ bn = (struct BNode *) ((u8 *) bn + btc->nodesize); >+ bn->key = cpu_to_be32(key); >+ btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) + 1); >+ break; >+ } else >+ memmove((u8 *)bn + btc->nodesize, bn, btc->nodesize); >+ >+ bn = (struct BNode *) ((u8 *) bn - btc->nodesize); >+ } >+ >+ return bn; >+} >+ >+static int getparentbtreecontainer(struct super_block *sb, struct buffer_head *bh, struct buffer_head **parent_bh) >+{ >+ u32 rootblock = ASFS_SB(sb)->extentbnoderoot; >+ u32 childkey = be32_to_cpu(((struct fsBNodeContainer *) bh->b_data)->btc.bnode[0].key); >+ u32 childblock = be32_to_cpu(((struct fsBNodeContainer *) bh->b_data)->bheader.ownblock); >+ >+ asfs_debug("getparentbtreecontainer: Getting parent of block %d\n", childblock); >+ >+ /* This function gets the BTreeContainer parent of the passed in buffer_head. If >+ there is no parent this function sets dest_cont io_bh to NULL */ >+ >+ if (rootblock != childblock) { >+ while ((*parent_bh = asfs_breadcheck(sb, rootblock, ASFS_BNODECONTAINER_ID))) { >+ struct fsBNodeContainer *bnc = (void *) (*parent_bh)->b_data; >+ struct BTreeContainer *btc = &bnc->btc; >+ struct BNode *bn; >+ s16 n = be16_to_cpu(btc->nodecount); >+ >+ if (btc->isleaf == TRUE) { >+ asfs_brelse(*parent_bh); >+ break; >+ } >+ >+ while (n-- > 0) >+ if (be32_to_cpu(btc->bnode[n].data) == childblock) >+ return 0; /* Found parent!! */ >+ >+ bn = searchforbnode(childkey, btc); /* This searchforbnode() doesn't have to get EXACT key matches. */ >+ rootblock = be32_to_cpu(bn->data); >+ asfs_brelse(*parent_bh); >+ } >+ if (*parent_bh == NULL) >+ return -EIO; >+ } >+ >+ *parent_bh = NULL; >+ return 0; >+} >+ >+/* Spits a btreecontainer. It realses passed in bh! */ >+ >+static int splitbtreecontainer(struct super_block *sb, struct buffer_head *bh) >+{ >+ struct buffer_head *bhparent; >+ struct BNode *bn; >+ int errorcode; >+ >+ asfs_debug("splitbtreecontainer: splitting block %u\n", be32_to_cpu(((struct fsBlockHeader *) bh->b_data)->ownblock)); >+ >+ if ((errorcode = getparentbtreecontainer(sb, bh, &bhparent)) == 0) { >+ if (bhparent == NULL) { >+ u32 newbcontblock; >+ u32 bcontblock; >+ /* We need to create Root tree-container - adding new level to extent tree */ >+ >+ asfs_debug("splitbtreecontainer: creating root tree-container.\n"); >+ >+ bhparent = bh; >+ if ((errorcode = allocadminspace(sb, &newbcontblock)) == 0 && (bh = asfs_getzeroblk(sb, newbcontblock))) { >+ struct fsBNodeContainer *bnc = (void *) bh->b_data; >+ struct fsBNodeContainer *bncparent = (void *) bhparent->b_data; >+ struct BTreeContainer *btcparent = &bncparent->btc; >+ >+ bcontblock = be32_to_cpu(bncparent->bheader.ownblock); >+ memcpy(bh->b_data, bhparent->b_data, sb->s_blocksize); >+ bnc->bheader.ownblock = cpu_to_be32(newbcontblock); >+ asfs_bstore(sb, bh); >+ >+ memset(bhparent->b_data, '\0', sb->s_blocksize); /* Not strictly needed, but makes things more clear. */ >+ bncparent->bheader.id = cpu_to_be32(ASFS_BNODECONTAINER_ID); >+ bncparent->bheader.ownblock = cpu_to_be32(bcontblock); >+ btcparent->isleaf = FALSE; >+ btcparent->nodesize = sizeof(struct BNode); >+ btcparent->nodecount = 0; >+ >+ bn = insertbnode(0, btcparent); >+ bn->data = cpu_to_be32(newbcontblock); >+ >+ asfs_bstore(sb, bhparent); >+ } >+ if (bh == NULL) >+ errorcode = -EIO; >+ } >+ >+ if (errorcode == 0) { >+ struct fsBNodeContainer *bncparent = (void *) bhparent->b_data; >+ struct BTreeContainer *btcparent = &bncparent->btc; >+ int branches1 = (sb->s_blocksize - sizeof(struct fsBNodeContainer)) / btcparent->nodesize; >+ >+ if (be16_to_cpu(btcparent->nodecount) == branches1) { >+ /* We need to split the parent tree-container first! */ >+ if ((errorcode = splitbtreecontainer(sb, bhparent)) == 0) { >+ /* bhparent might have changed after the split and has been released */ >+ if ((errorcode = getparentbtreecontainer(sb, bh, &bhparent)) == 0) { >+ bncparent = (void *) bhparent->b_data; >+ btcparent = &bncparent->btc; >+ } >+ } >+ } >+ >+ if (errorcode == 0) { >+ u32 newbcontblock; >+ struct buffer_head *bhnew; >+ >+ /* We can split this container and add it to the parent >+ because the parent has enough room. */ >+ >+ if ((errorcode = allocadminspace(sb, &newbcontblock)) == 0 && (bhnew = asfs_getzeroblk(sb, newbcontblock))) { >+ struct fsBNodeContainer *bncnew = (void *) bhnew->b_data; >+ struct BTreeContainer *btcnew = &bncnew->btc; >+ struct fsBNodeContainer *bnc = (void *) bh->b_data; >+ struct BTreeContainer *btc = &bnc->btc; >+ int branches2 = (sb->s_blocksize - sizeof(struct fsBNodeContainer)) / btc->nodesize; >+ u32 newkey; >+ >+ bncnew->bheader.id = cpu_to_be32(ASFS_BNODECONTAINER_ID); >+ bncnew->bheader.ownblock = cpu_to_be32(newbcontblock); >+ >+ btcnew->isleaf = btc->isleaf; >+ btcnew->nodesize = btc->nodesize; >+ >+ btcnew->nodecount = cpu_to_be16(branches2 - branches2 / 2); >+ >+ memcpy(btcnew->bnode, (u8 *) btc->bnode + branches2 / 2 * btc->nodesize, (branches2 - branches2 / 2) * btc->nodesize); >+ newkey = be32_to_cpu(btcnew->bnode[0].key); >+ >+ asfs_bstore(sb, bhnew); >+ asfs_brelse(bhnew); >+ >+ btc->nodecount = cpu_to_be16(branches2 / 2); >+ asfs_bstore(sb, bh); >+ >+ bn = insertbnode(newkey, btcparent); >+ bn->data = cpu_to_be32(newbcontblock); >+ asfs_bstore(sb, bhparent); >+ } >+ } >+ } >+ asfs_brelse(bhparent); >+ } >+ asfs_brelse(bh); >+ >+ return errorcode; >+} >+ >+/* zwraca wstawiony node w bloku, zapisaƦ trzeba samemu! */ >+int createextentbnode(struct super_block *sb, u32 key, struct buffer_head **returned_bh, struct BNode **returned_bnode) >+{ >+ int errorcode; >+ >+ asfs_debug("createbnode: Creating BNode with key %d\n", key); >+ >+ while ((errorcode = findbnode(sb, key, returned_bh, returned_bnode)) == 0) { >+ struct fsBNodeContainer *bnc = (void *) (*returned_bh)->b_data; >+ struct BTreeContainer *btc = &bnc->btc; >+ int extbranches = (sb->s_blocksize - sizeof(struct fsBNodeContainer)) / btc->nodesize; >+ >+ asfs_debug("createbnode: findbnode found block %d\n", be32_to_cpu(((struct fsBlockHeader *) (*returned_bh)->b_data)->ownblock)); >+ >+ if (be16_to_cpu(btc->nodecount) < extbranches) { >+ /* Simply insert new node in this BTreeContainer */ >+ asfs_debug("createbnode: Simple insert\n"); >+ *returned_bnode = insertbnode(key, btc); >+ break; >+ } else if ((errorcode = splitbtreecontainer(sb, *returned_bh)) != 0) >+ break; >+ >+ /* Loop and try insert it the normal way again :-) */ >+ } >+ >+ return (errorcode); >+} >+ >+ >+/* This routine removes a node from a BTreeContainer indentified >+ by its key. If no such key exists this routine does nothing. >+ It correctly handles empty BTreeContainers. */ >+ >+static void removebnode(u32 key, struct BTreeContainer *btc) >+{ >+ struct BNode *bn = btc->bnode; >+ int n = 0; >+ >+ asfs_debug("removebnode: key %d\n", key); >+ >+ while (n < be16_to_cpu(btc->nodecount)) { >+ if (be32_to_cpu(bn->key) == key) { >+ btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) - 1); >+ memmove(bn, (u8 *) bn + btc->nodesize, (be16_to_cpu(btc->nodecount) - n) * btc->nodesize); >+ break; >+ } >+ bn = (struct BNode *) ((u8 *) bn + btc->nodesize); >+ n++; >+ } >+} >+ >+int deletebnode(struct super_block *sb, struct buffer_head *bh, u32 key) >+{ >+ struct fsBNodeContainer *bnc1 = (void *) bh->b_data; >+ struct BTreeContainer *btc = &bnc1->btc; >+ u16 branches = (sb->s_blocksize - sizeof(struct fsBNodeContainer)) / btc->nodesize; >+ int errorcode = 0; >+ >+ /* Deletes specified internal node. */ >+ >+ removebnode(key, btc); >+ asfs_bstore(sb, bh); >+ >+ /* Now checks if the container still contains enough nodes, >+ and takes action accordingly. */ >+ >+ asfs_debug("deletebnode: branches = %d, btc->nodecount = %d\n", branches, be16_to_cpu(btc->nodecount)); >+ >+ if (be16_to_cpu(btc->nodecount) < (branches + 1) / 2) { >+ struct buffer_head *bhparent; >+ struct buffer_head *bhsec; >+ >+ /* nodecount has become to low. We need to merge this Container >+ with a neighbouring Container, or we need to steal a few nodes >+ from a neighbouring Container. */ >+ >+ /* We get the parent of the container here, so we can find out what >+ containers neighbour the container which currently hasn't got enough nodes. */ >+ >+ if ((errorcode = getparentbtreecontainer(sb, bh, &bhparent)) == 0) { >+ if (bhparent != NULL) { >+ struct fsBNodeContainer *bncparent = (void *) bhparent->b_data; >+ struct BTreeContainer *btcparent = &bncparent->btc; >+ s16 n; >+ >+ asfs_debug("deletebnode: get parent returned block %d.\n", be32_to_cpu(((struct fsBlockHeader *) bhparent->b_data)->ownblock)); >+ >+ for (n = 0; n < be16_to_cpu(btcparent->nodecount); n++) >+ if (btcparent->bnode[n].data == bnc1->bheader.ownblock) >+ break; >+ /* n is now the offset of our own bnode. */ >+ >+ if (n < be16_to_cpu(btcparent->nodecount) - 1) { /* Check if we have a next neighbour. */ >+ asfs_debug("deletebnode: using next container - merging blocks %d and %d\n", be32_to_cpu(bnc1->bheader.ownblock), be32_to_cpu(btcparent->bnode[n+1].data)); >+ >+ if ((bhsec = asfs_breadcheck(sb, be32_to_cpu(btcparent->bnode[n + 1].data), ASFS_BNODECONTAINER_ID))) { >+ struct fsBNodeContainer *bnc_next = (void *) bhsec->b_data; >+ struct BTreeContainer *btc_next = &bnc_next->btc; >+ >+ if (be16_to_cpu(btc_next->nodecount) + be16_to_cpu(btc->nodecount) > branches) { /* Check if we need to steal nodes. */ >+ s16 nodestosteal = (be16_to_cpu(btc_next->nodecount) + be16_to_cpu(btc->nodecount)) / 2 - be16_to_cpu(btc->nodecount); >+ >+ /* Merging them is not possible. Steal a few nodes then. */ >+ memcpy((u8 *) btc->bnode + be16_to_cpu(btc->nodecount) * btc->nodesize, btc_next->bnode, nodestosteal * btc->nodesize); >+ btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) + nodestosteal); >+ asfs_bstore(sb, bh); >+ >+ memcpy(btc_next->bnode, (u8 *) btc_next->bnode + btc_next->nodesize * nodestosteal, >+ btc->nodesize * (be16_to_cpu(btc_next->nodecount) - nodestosteal)); >+ btc_next->nodecount = cpu_to_be16(be16_to_cpu(btc_next->nodecount) - nodestosteal); >+ asfs_bstore(sb, bhsec); >+ >+ btcparent->bnode[n + 1].key = btc_next->bnode[0].key; >+ asfs_bstore(sb, bhparent); >+ } else { /* Merging is possible. */ >+ memcpy((u8 *) btc->bnode + btc->nodesize * be16_to_cpu(btc->nodecount), btc_next->bnode, btc->nodesize * be16_to_cpu(btc_next->nodecount)); >+ btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) + be16_to_cpu(btc_next->nodecount)); >+ asfs_bstore(sb, bh); >+ >+ if ((errorcode = freeadminspace(sb, be32_to_cpu(((struct fsBlockHeader *) bhsec->b_data)->ownblock))) == 0) >+ errorcode = deletebnode(sb, bhparent, be32_to_cpu(btcparent->bnode[n + 1].key)); >+ } >+ asfs_brelse(bhsec); >+ } >+ } else if (n > 0) { /* Check if we have a previous neighbour. */ >+ asfs_debug("deletebnode: using prev container.\n"); >+ >+ if ((bhsec = asfs_breadcheck(sb, be32_to_cpu(btcparent->bnode[n - 1].data), ASFS_BNODECONTAINER_ID)) == 0) { >+ struct fsBNodeContainer *bnc2 = (void *) bhsec->b_data; >+ struct BTreeContainer *btc2 = &bnc2->btc; >+ >+ if (be16_to_cpu(btc2->nodecount) + be16_to_cpu(btc->nodecount) > branches) { >+ /* Merging them is not possible. Steal a few nodes then. */ >+ s16 nodestosteal = (be16_to_cpu(btc2->nodecount) + be16_to_cpu(btc->nodecount)) / 2 - be16_to_cpu(btc->nodecount); >+ >+ memmove((u8 *) btc->bnode + nodestosteal * btc->nodesize, btc->bnode, be16_to_cpu(btc->nodecount) * btc->nodesize); >+ btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) + nodestosteal); >+ memcpy(btc->bnode, (u8 *) btc2->bnode + (be16_to_cpu(btc2->nodecount) - nodestosteal) * btc2->nodesize, nodestosteal * btc->nodesize); >+ >+ asfs_bstore(sb, bh); >+ >+ btc2->nodecount = cpu_to_be16(be16_to_cpu(btc2->nodecount) - nodestosteal); >+ asfs_bstore(sb, bhsec); >+ >+ btcparent->bnode[n].key = btc->bnode[0].key; >+ asfs_bstore(sb, bhparent); >+ } else { /* Merging is possible. */ >+ memcpy((u8 *) btc2->bnode + be16_to_cpu(btc2->nodecount) * btc2->nodesize, btc->bnode, be16_to_cpu(btc->nodecount) * btc->nodesize); >+ btc2->nodecount = cpu_to_be16(be16_to_cpu(btc2->nodecount) + be16_to_cpu(btc->nodecount)); >+ asfs_bstore(sb, bhsec); >+ >+ if ((errorcode = freeadminspace(sb, be32_to_cpu(((struct fsBlockHeader *) bhsec->b_data)->ownblock))) == 0) >+ errorcode = deletebnode(sb, bhparent, be32_to_cpu(btcparent->bnode[n].key)); >+ } >+ asfs_brelse(bhsec); >+ } >+ } >+ /* else >+ { >+ // Never happens, except for root and then we don't care. >+ } */ >+ } else if (btc->nodecount == 1) { >+ /* No parent, so must be root. */ >+ >+ asfs_debug("deletebnode: no parent so must be root\n"); >+ >+ if (btc->isleaf == FALSE) { >+ struct fsBNodeContainer *bnc3 = (void *) bh->b_data; >+ >+ /* The current root has only 1 node. We now copy the data of this node into the >+ root and promote that data to be the new root. The rootblock number stays the >+ same that way. */ >+ >+ if ((bhsec = asfs_breadcheck(sb, be32_to_cpu(btc->bnode[0].data), ASFS_BNODECONTAINER_ID))) { >+ u32 blockno = be32_to_cpu(((struct fsBlockHeader *) bh->b_data)->ownblock); >+ memcpy(bh->b_data, bhsec->b_data, sb->s_blocksize); >+ bnc3->bheader.ownblock = cpu_to_be32(blockno); >+ >+ asfs_bstore(sb, bh); >+ errorcode = freeadminspace(sb, be32_to_cpu(((struct fsBlockHeader *) bhsec->b_data)->ownblock)); >+ asfs_brelse(bhsec); >+ } else >+ errorcode = -EIO; >+ } >+ /* If not, then root contains leafs. */ >+ } >+ >+ asfs_debug("deletebnode: almost done\n"); >+ /* otherwise, it must be the root, and the root is allowed >+ to contain less than the minimum amount of nodes. */ >+ >+ } >+ if (bhparent != NULL) >+ asfs_brelse(bhparent); >+ } >+ >+ return errorcode; >+} >+ >+ /* Deletes an fsExtentBNode structure by key and any fsExtentBNodes linked to it. >+ This function DOES NOT fix the next pointer in a possible fsExtentBNode which >+ might have been pointing to the first BNode we are deleting. Make sure you check >+ this yourself, if needed. >+ >+ If key is zero, than this function does nothing. */ >+ >+int deleteextents(struct super_block *sb, u32 key) >+{ >+ struct buffer_head *bh; >+ struct fsExtentBNode *ebn; >+ int errorcode = 0; >+ >+ asfs_debug("deleteextents: Entry -- deleting extents from key %d\n", key); >+ >+ while (key != 0 && (errorcode = findbnode(sb, key, &bh, (struct BNode **) &ebn)) == 0) { >+ /* node to be deleted located. */ >+ key = be32_to_cpu(ebn->next); >+ if ((errorcode = freespace(sb, be32_to_cpu(ebn->key), be16_to_cpu(ebn->blocks))) != 0) >+ break; >+ >+ if ((errorcode = deletebnode(sb, bh, be32_to_cpu(ebn->key))) != 0) >+ break; >+ >+ asfs_brelse(bh); >+ } >+ >+ return (errorcode); >+} >+ >+ /* This function adds /blocks/ blocks starting at block /newspace/ to a file >+ identified by /objectnode/ and /lastextentbnode/. /io_lastextentbnode/ can >+ be zero if there is no ExtentBNode chain attached to this file yet. >+ /blocks/ ranges from 1 to 8192. To be able to extend Extents which are >+ almost full, it is wise to make this value no higher than 8192 blocks. >+ /io_lastextentbnode/ will contain the new lastextentbnode value when this >+ function completes. >+ If there was no chain yet, then this function will create a new one. */ >+ >+int addblocks(struct super_block *sb, u16 blocks, u32 newspace, u32 objectnode, u32 *io_lastextentbnode) >+{ >+ struct buffer_head *bh; >+ struct fsExtentBNode *ebn; >+ int errorcode = 0; >+ >+ if (*io_lastextentbnode != 0) { >+ /* There was already a ExtentBNode chain for this file. Extending it. */ >+ >+ asfs_debug(" addblocks: Extending existing ExtentBNode chain.\n"); >+ >+ if ((errorcode = getextent(sb, *io_lastextentbnode, &bh, &ebn)) == 0) { >+ if (be32_to_cpu(ebn->key) + be16_to_cpu(ebn->blocks) == newspace && be16_to_cpu(ebn->blocks) + blocks < 65536) { >+ /* It is possible to extent the last ExtentBNode! */ >+ asfs_debug(" addblocks: Extending last ExtentBNode.\n"); >+ >+ ebn->blocks = cpu_to_be16(be16_to_cpu(ebn->blocks) + blocks); >+ >+ asfs_bstore(sb, bh); >+ asfs_brelse(bh); >+ } else { >+ /* It isn't possible to extent the last ExtentBNode so we create >+ a new one and link it to the last ExtentBNode. */ >+ >+ ebn->next = cpu_to_be32(newspace); >+ asfs_bstore(sb, bh); >+ asfs_brelse(bh); >+ >+ if ((errorcode = createextentbnode(sb, newspace, &bh, (struct BNode **) &ebn)) == 0) { >+ asfs_debug(" addblocks: Created new ExtentBNode.\n"); >+ >+ ebn->key = cpu_to_be32(newspace); >+ ebn->prev = cpu_to_be32(*io_lastextentbnode); >+ ebn->next = 0; >+ ebn->blocks = cpu_to_be16(blocks); >+ >+ *io_lastextentbnode = newspace; >+ >+ asfs_bstore(sb, bh); >+ asfs_brelse(bh); >+ >+ ASFS_SB(sb)->block_rovingblockptr = newspace + blocks; >+ >+ /* to be changed in the future */ >+/* if (ASFS_SB(sb)->block_rovingblockptr >= ASFS_SB(sb)->totalblocks) >+ ASFS_SB(sb)->block_rovingblockptr = 0;*/ >+ } >+ } >+ } >+ } else { >+ /* There is no ExtentBNode chain yet for this file. Attaching one! */ >+ if ((errorcode = createextentbnode(sb, newspace, &bh, (struct BNode **) &ebn)) == 0) { >+ asfs_debug(" addblocks: Created new ExtentBNode chain.\n"); >+ >+ ebn->key = cpu_to_be32(newspace); >+ ebn->prev = cpu_to_be32(objectnode + 0x80000000); >+ ebn->next = 0; >+ ebn->blocks = cpu_to_be16(blocks); >+ >+ *io_lastextentbnode = newspace; >+ >+ asfs_bstore(sb, bh); >+ asfs_brelse(bh); >+ >+ ASFS_SB(sb)->block_rovingblockptr = newspace + blocks; >+ >+/* if (ASFS_SB(sb)->block_rovingblockptr >= ASFS_SB(sb)->totalblocks) >+ ASFS_SB(sb)->block_rovingblockptr = 0;*/ >+ } >+ } >+ >+ asfs_debug(" addblocks: done.\n"); >+ >+ return errorcode; >+} >+#endif >diff -urN kernel-source-2.6.5/fs/asfs/file.c kernel-source-2.6.5-powerpc/fs/asfs/file.c >--- kernel-source-2.6.5/fs/asfs/file.c 1970-01-01 01:00:00.000000000 +0100 >+++ kernel-source-2.6.5-powerpc/fs/asfs/file.c 2004-04-12 23:39:01.000000000 +0200 >@@ -0,0 +1,256 @@ >+/* >+ * >+ * Amiga Smart File System, Linux implementation >+ * version: 1.0beta3 >+ * >+ * Copyright (C) 2003,2004 Marek 'March' Szyprowski <marek@amiga.pl> >+ * >+ * >+ * 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/asfs_fs.h> >+#include <linux/fs.h> >+#include <linux/pagemap.h> >+#include <linux/buffer_head.h> >+#include <linux/vfs.h> >+ >+#include <asm/byteorder.h> >+ >+static int >+asfs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_result, int create) >+{ >+ struct buffer_head *ebn_bh; >+ struct fsExtentBNode extent, *ebn_p; >+ u32 filedata; >+ unsigned long pos; >+ struct super_block *sb = inode->i_sb; >+#ifdef CONFIG_ASFS_RW >+ int error; >+ struct buffer_head *bh; >+ struct fsObject *obj; >+#endif >+ >+ asfs_debug("ASFS: get_block(%lu, %ld, %d)\n", inode->i_ino, block, create); >+ >+ if (block < 0) { >+ printk(KERN_ERR "ASFS: asfsget_block: requested block (%ld) < 0!\n", block); >+ return -EIO; >+ } else if (block >= inode->i_blocks && !create) { >+ printk(KERN_ERR "ASFS: asfsget_block: strange block request %ld!\n", block); >+ return -EIO; >+ } >+ >+ if (create) >+#ifdef CONFIG_ASFS_RW >+ ASFS_I(inode)->modified = TRUE; >+#else >+ return -EROFS; >+#endif >+ >+ if (block < inode->i_blocks) >+ create = 0; >+ >+ lock_super(sb); >+ >+#ifdef CONFIG_ASFS_RW >+ if (create) { >+ int blockstoadd; >+ u32 newspace, addedblocks; >+ >+ blockstoadd = block - inode->i_blocks + 1; >+ >+ if (blockstoadd < ASFS_BLOCKCHUNKS) >+ blockstoadd = ASFS_BLOCKCHUNKS; >+ >+ asfs_debug("ASFS get_block: Trying to add %d blocks to file\n", blockstoadd); >+ >+ if ((error = readobject(sb, inode->i_ino, &bh, &obj)) != 0) { >+ unlock_super(sb); >+ return error; >+ } >+ >+ if ((error = addblockstofile(sb, bh, obj, blockstoadd, &newspace, &addedblocks)) != 0) { >+ asfs_brelse(bh); >+ unlock_super(sb); >+ return error; >+ } >+ ASFS_I(inode)->mmu_private += addedblocks * sb->s_blocksize; >+ inode->i_blocks += addedblocks; >+ ASFS_I(inode)->ext_cache.key = 0; >+ ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data); >+ asfs_brelse(bh); >+ } >+#endif >+ >+ if (ASFS_I(inode)->ext_cache.key > 0 && ASFS_I(inode)->ext_cache.startblock <= block) { >+ extent.key = ASFS_I(inode)->ext_cache.key; >+ extent.next = ASFS_I(inode)->ext_cache.next; >+ extent.blocks = ASFS_I(inode)->ext_cache.blocks; >+ pos = ASFS_I(inode)->ext_cache.startblock; >+ } else { >+ if (getextent(inode->i_sb, ASFS_I(inode)->firstblock, &ebn_bh, &ebn_p) != 0) { >+ unlock_super(sb); >+ return -EIO; >+ } >+ extent.key = be32_to_cpu(ebn_p->key); >+ extent.next = be32_to_cpu(ebn_p->next); >+ extent.blocks = be16_to_cpu(ebn_p->blocks); >+ pos = 0; >+ asfs_brelse(ebn_bh); >+ } >+ ebn_p = &extent; >+ filedata = ebn_p->next; >+ >+ while (pos + ebn_p->blocks <= block && ebn_p->next != 0 && pos < inode->i_blocks) { >+ pos += ebn_p->blocks; >+ if (getextent(inode->i_sb, filedata, &ebn_bh, &ebn_p) != 0) { >+ unlock_super(sb); >+ return -EIO; >+ } >+ extent.key = be32_to_cpu(ebn_p->key); >+ extent.next = be32_to_cpu(ebn_p->next); >+ extent.blocks = be16_to_cpu(ebn_p->blocks); >+ ebn_p = &extent; >+ filedata = ebn_p->next; >+ asfs_brelse(ebn_bh); >+ } >+ >+ unlock_super(sb); >+ >+ map_bh(bh_result, inode->i_sb, (sector_t) (ebn_p->key + block - pos)); >+ >+ if (create) >+ set_buffer_new(bh_result); >+ >+ asfs_debug("ASFS: get_block - mapped block %lu\n", ebn_p->key + block - pos); >+ >+ ASFS_I(inode)->ext_cache.startblock = pos; >+ ASFS_I(inode)->ext_cache.key = ebn_p->key; >+ ASFS_I(inode)->ext_cache.next = ebn_p->next; >+ ASFS_I(inode)->ext_cache.blocks = ebn_p->blocks; >+ >+ return 0; >+} >+ >+int asfs_readpage(struct file *file, struct page *page) >+{ >+ asfs_debug(__FUNCTION__ "\n"); >+ return block_read_full_page(page, asfs_get_block); >+} >+ >+sector_t asfs_bmap(struct address_space *mapping, sector_t block) >+{ >+ asfs_debug(__FUNCTION__ "\n"); >+ return generic_block_bmap(mapping,block,asfs_get_block); >+} >+ >+#ifdef CONFIG_ASFS_RW >+ >+int asfs_writepage(struct page *page, struct writeback_control *wbc) >+{ >+ asfs_debug(__FUNCTION__ "\n"); >+ return block_write_full_page(page, asfs_get_block, wbc); >+} >+ >+int asfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) >+{ >+ asfs_debug(__FUNCTION__ "\n"); >+ return cont_prepare_write(page, from, to, asfs_get_block, &ASFS_I(page->mapping->host)->mmu_private); >+} >+ >+void asfs_truncate(struct inode *inode) >+{ >+ struct super_block *sb = inode->i_sb; >+ struct buffer_head *bh; >+ struct fsObject *obj; >+ >+ asfs_debug("AFFS: truncate(inode=%d, oldsize=%u, newsize=%u)\n", >+ (u32)inode->i_ino, (u32)ASFS_I(inode)->mmu_private, (u32)inode->i_size); >+ >+ if (inode->i_size > ASFS_I(inode)->mmu_private) { >+ printk("ASFS: enlarging file is not supported yet\n"); >+ return; >+ } >+ >+ lock_super(sb); >+ >+ if ((readobject(sb, inode->i_ino, &bh, &obj)) != 0) { >+ unlock_super(sb); >+ return; >+ } >+ >+ if (truncateblocksinfile(sb, bh, obj, inode->i_size) != 0) { >+ asfs_brelse(bh); >+ unlock_super(sb); >+ return; >+ } >+ >+ obj->object.file.size = cpu_to_be32(inode->i_size); >+ ASFS_I(inode)->mmu_private = inode->i_size; >+ ASFS_I(inode)->modified = TRUE; >+ inode->i_blocks = (be32_to_cpu(obj->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits; >+ asfs_bstore(sb, bh); >+ asfs_brelse(bh); >+ >+ unlock_super(sb); >+} >+ >+int asfs_file_open(struct inode *inode, struct file *filp) >+{ >+ if (atomic_read(&filp->f_count) != 1) >+ return 0; >+ asfs_debug("ASFS: file open (node %d)\n", (int)inode->i_ino); >+ ASFS_I(inode)->i_opencnt++; >+ return 0; >+} >+ >+int asfs_file_release(struct inode *inode, struct file *filp) >+{ >+ int error = 0; >+ >+ if (atomic_read(&filp->f_count) != 0) >+ return 0; >+ >+ ASFS_I(inode)->i_opencnt--; >+ if (ASFS_I(inode)->i_opencnt) >+ return 0; >+ >+ asfs_debug("ASFS: file release (node %d)\n", (int)inode->i_ino); >+ >+ if (ASFS_I(inode)->modified == TRUE) { >+ struct buffer_head *bh; >+ struct fsObject *obj; >+ lock_super(inode->i_sb); >+ >+ if ((error = readobject(inode->i_sb, inode->i_ino, &bh, &obj)) != 0) { >+ unlock_super(inode->i_sb); >+ return error; >+ } >+ >+ obj->datemodified = cpu_to_be32(inode->i_mtime.tv_sec - (365*8+2)*24*60*60); >+ if (inode->i_mode & S_IFREG) { >+ error = truncateblocksinfile(inode->i_sb, bh, obj, (u32)inode->i_size); >+ obj->object.file.size = cpu_to_be32(inode->i_size); >+ ASFS_I(inode)->mmu_private = inode->i_size; >+ inode->i_blocks = (be32_to_cpu(obj->object.file.size) + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits; >+ } >+ asfs_bstore(inode->i_sb, bh); >+ >+ unlock_super(inode->i_sb); >+ >+ asfs_brelse(bh); >+ } >+ ASFS_I(inode)->modified = FALSE; >+ >+ return error; >+} >+ >+#endif >diff -urN kernel-source-2.6.5/fs/asfs/inode.c kernel-source-2.6.5-powerpc/fs/asfs/inode.c >--- kernel-source-2.6.5/fs/asfs/inode.c 1970-01-01 01:00:00.000000000 +0100 >+++ kernel-source-2.6.5-powerpc/fs/asfs/inode.c 2004-04-12 23:39:01.000000000 +0200 >@@ -0,0 +1,487 @@ >+/* >+ * >+ * Amiga Smart File System, Linux implementation >+ * version: 1.0beta4 >+ * >+ * Copyright (C) 2003,2004 Marek 'March' Szyprowski <marek@amiga.pl> >+ * >+ * >+ * 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/asfs_fs.h> >+#include <linux/fs.h> >+#include <linux/smp_lock.h> >+#include <linux/time.h> >+#include <linux/buffer_head.h> >+#include <linux/vfs.h> >+#include <linux/dirent.h> >+ >+#include <asm/byteorder.h> >+ >+/* Mapping from our types to the kernel */ >+ >+static struct address_space_operations asfs_aops = { >+ .readpage = asfs_readpage, >+ .sync_page = block_sync_page, >+ .bmap = asfs_bmap, >+#ifdef CONFIG_ASFS_RW >+ .writepage = asfs_writepage, >+ .prepare_write = asfs_prepare_write, >+ .commit_write = generic_commit_write, >+#endif >+}; >+ >+struct file_operations asfs_file_operations = { >+ .llseek = generic_file_llseek, >+ .read = generic_file_read, >+ .mmap = generic_file_mmap, >+#ifdef CONFIG_ASFS_RW >+ .write = generic_file_write, >+ .open = asfs_file_open, >+ .release = asfs_file_release, >+ .fsync = file_fsync, >+#endif >+}; >+ >+static struct file_operations asfs_dir_operations = { >+ .read = generic_read_dir, >+ .readdir = asfs_readdir, >+}; >+ >+static struct inode_operations asfs_dir_inode_operations = { >+ .lookup = asfs_lookup, >+#ifdef CONFIG_ASFS_RW >+ .create = asfs_create, >+ .unlink = asfs_delete, >+ .symlink = asfs_symlink, >+ .mkdir = asfs_mkdir, >+ .rmdir = asfs_rmdir, >+ .rename = asfs_rename, >+/* .setattr = asfs_notify_change,*/ >+#endif >+}; >+ >+static struct inode_operations asfs_file_inode_operations = { >+#ifdef CONFIG_ASFS_RW >+ .truncate = asfs_truncate, >+/* .setattr = asfs_notify_change,*/ >+#endif >+}; >+ >+struct address_space_operations asfs_symlink_aops = { >+ .readpage = asfs_symlink_readpage, >+}; >+ >+static struct inode_operations asfs_symlink_inode_operations = { >+ .readlink = page_readlink, >+ .follow_link = page_follow_link, >+#ifdef CONFIG_ASFS_RW >+/* .setattr = asfs_notify_change,*/ >+#endif >+}; >+ >+void asfs_read_locked_inode(struct inode *inode, void *arg) >+{ >+ struct super_block *sb = inode->i_sb; >+ struct fsObject *obj = arg; >+ >+ inode->i_mode = ASFS_SB(sb)->mode; >+ inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = be32_to_cpu(obj->datemodified) + (365*8+2)*24*60*60; >+ /* Linux: seconds since 01-01-1970, AmigaSFS: seconds since 01-01-1978 */ >+ inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_atime.tv_nsec = 0; >+ inode->i_uid = ASFS_SB(sb)->uid; >+ inode->i_gid = ASFS_SB(sb)->gid; >+ >+ ASFS_I(inode)->i_opencnt = 0; >+ >+ asfs_debug("asfs_read_inode2: Setting-up node %lu... ", inode->i_ino); >+ >+ if (obj->bits & OTYPE_DIR) { >+ asfs_debug("dir (FirstdirBlock: %u, HashTable %u)\n", \ >+ be32_to_cpu(obj->object.dir.firstdirblock), be32_to_cpu(obj->object.dir.hashtable)); >+ >+ inode->i_size = 0; >+ inode->i_op = &asfs_dir_inode_operations; >+ inode->i_fop = &asfs_dir_operations; >+ inode->i_mode |= S_IFDIR | ((inode->i_mode & 0400) ? 0100 : 0) | >+ ((inode->i_mode & 0040) ? 0010 : 0) | ((inode->i_mode & 0004) ? 0001 : 0); >+ ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.dir.firstdirblock); >+ ASFS_I(inode)->hashtable = be32_to_cpu(obj->object.dir.hashtable); >+ ASFS_I(inode)->modified = 0; >+ } else if (obj->bits & OTYPE_LINK && !(obj->bits & OTYPE_HARDLINK)) { >+ asfs_debug("symlink\n"); >+ inode->i_size = 0; >+ inode->i_op = &asfs_symlink_inode_operations; >+ inode->i_mapping->a_ops = &asfs_symlink_aops; >+ inode->i_mode |= S_IFLNK | S_IRWXUGO; >+ ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data); >+ } else { >+ asfs_debug("file (Size: %u, FirstBlock: %u)\n", be32_to_cpu(obj->object.file.size), be32_to_cpu(obj->object.file.data)); >+ inode->i_size = be32_to_cpu(obj->object.file.size); >+ inode->i_blocks = (be32_to_cpu(obj->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits; >+ inode->i_op = &asfs_file_inode_operations; >+ inode->i_fop = &asfs_file_operations; >+ inode->i_mapping->a_ops = &asfs_aops; >+ inode->i_mode |= S_IFREG; >+ ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data); >+ ASFS_I(inode)->ext_cache.startblock = 0; >+ ASFS_I(inode)->ext_cache.key = 0; >+ ASFS_I(inode)->mmu_private = inode->i_size; >+ } >+ return; >+} >+ >+struct inode *asfs_get_root_inode(struct super_block *sb) >+{ >+ struct inode *result = NULL; >+ struct fsObject *obj; >+ struct buffer_head *bh; >+ >+ asfs_debug("asfs_get_root_inode\n"); >+ >+ if ((bh = asfs_breadcheck(sb, ASFS_SB(sb)->rootobjectcontainer, ASFS_OBJECTCONTAINER_ID))) { >+ obj = &(((struct fsObjectContainer *)bh->b_data)->object[0]); >+ if (be32_to_cpu(obj->objectnode) > 0) >+ result = iget_locked(sb, be32_to_cpu(obj->objectnode)); >+ >+ if (result != NULL && result->i_state & I_NEW) { >+ asfs_read_locked_inode(result, obj); >+ unlock_new_inode(result); >+ } >+ >+ asfs_brelse(bh); >+ } >+ return result; >+} >+ >+#ifdef CONFIG_ASFS_RW >+ >+int asfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) >+{ >+ int error; >+ struct super_block *sb = dir->i_sb; >+ struct inode *inode; >+ struct buffer_head *bh, *dir_bh; >+ struct fsObject obj_data, *dir_obj, *obj; >+ u8 *name = (u8 *) dentry->d_name.name; >+ >+ asfs_debug("asfs_create %s in dir node %d\n", name, (int)dir->i_ino); >+ >+ sb = dir->i_sb; >+ inode = new_inode(sb); >+ if (!inode) >+ return -ENOMEM; >+ >+ inode->i_mode = mode; >+ inode->i_uid = current->fsuid; >+ inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; >+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; >+ inode->i_blocks = inode->i_blksize = 0; >+ >+ inode->i_fop = &asfs_file_operations; >+ inode->i_mapping->a_ops = &asfs_aops; >+ >+ memset(&obj_data, 0, sizeof(struct fsObject)); >+ >+ obj_data.protection = cpu_to_be32(FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE); >+ obj_data.datemodified = cpu_to_be32(inode->i_mtime.tv_sec - (365*8+2)*24*60*60); >+ >+ lock_super(sb); >+ >+ if ((error = readobject(sb, dir->i_ino, &dir_bh, &dir_obj)) != 0) { >+ dec_count(inode); >+ unlock_super(sb); >+ return error; >+ } >+ >+ bh = dir_bh; >+ obj = dir_obj; >+ >+ if ((error = createobject(sb, &bh, &obj, &obj_data, name, FALSE)) != 0) { >+ asfs_brelse(dir_bh); >+ dec_count(inode); >+ unlock_super(sb); >+ return error; >+ } >+ >+ inode->i_ino = be32_to_cpu(obj->objectnode); >+ >+ ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data); >+ ASFS_I(inode)->ext_cache.startblock = 0; >+ ASFS_I(inode)->ext_cache.key = 0; >+ >+ asfs_bstore(sb, bh); >+ >+ insert_inode_hash(inode); >+ mark_inode_dirty(inode); >+ >+ d_instantiate(dentry, inode); >+ ASFS_I(dir)->firstblock = be32_to_cpu(dir_obj->object.dir.firstdirblock); >+ ASFS_I(dir)->modified = 1; >+ dir->i_mtime = dir->i_ctime = inode->i_mtime; >+ dir_obj->datemodified = cpu_to_be32(inode->i_mtime.tv_sec - (365*8+2)*24*60*60); >+ asfs_bstore(sb, dir_bh); >+ >+ unlock_super(sb); >+ >+ asfs_brelse(bh); >+ asfs_brelse(dir_bh); >+ >+ return 0; >+} >+ >+int asfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) >+{ >+ int error; >+ struct super_block *sb = dir->i_sb; >+ struct inode *inode; >+ struct buffer_head *bh, *dir_bh; >+ struct fsObject obj_data, *dir_obj, *obj; >+ u8 *name = (u8 *) dentry->d_name.name; >+ >+ asfs_debug("asfs_create %s in dir node %d\n", name, (int)dir->i_ino); >+ >+ sb = dir->i_sb; >+ inode = new_inode(sb); >+ if (!inode) >+ return -ENOMEM; >+ >+ inode->i_mode = S_IFDIR | mode; >+ inode->i_uid = current->fsuid; >+ inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; >+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; >+ inode->i_blocks = inode->i_blksize = 0; >+ >+ inode->i_op = &asfs_dir_inode_operations; >+ inode->i_fop = &asfs_dir_operations; >+ >+ memset(&obj_data, 0, sizeof(struct fsObject)); >+ >+ obj_data.protection = cpu_to_be32(FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE); >+ obj_data.datemodified = cpu_to_be32(inode->i_mtime.tv_sec - (365*8+2)*24*60*60); >+ obj_data.bits = OTYPE_DIR; >+ >+ lock_super(sb); >+ >+ if ((error = readobject(sb, dir->i_ino, &dir_bh, &dir_obj)) != 0) { >+ dec_count(inode); >+ unlock_super(sb); >+ return error; >+ } >+ >+ bh = dir_bh; >+ obj = dir_obj; >+ >+ if ((error = createobject(sb, &bh, &obj, &obj_data, name, FALSE)) != 0) { >+ asfs_brelse(dir_bh); >+ dec_count(inode); >+ unlock_super(sb); >+ return error; >+ } >+ >+ inode->i_ino = be32_to_cpu(obj->objectnode); >+ ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.dir.firstdirblock); >+ ASFS_I(inode)->hashtable = be32_to_cpu(obj->object.dir.hashtable); >+ >+ asfs_bstore(sb, bh); >+ >+ insert_inode_hash(inode); >+ mark_inode_dirty(inode); >+ >+ d_instantiate(dentry, inode); >+ ASFS_I(dir)->firstblock = be32_to_cpu(dir_obj->object.dir.firstdirblock); >+ ASFS_I(dir)->modified = 1; >+ dir->i_mtime = dir->i_ctime = inode->i_mtime; >+ dir_obj->datemodified = cpu_to_be32(inode->i_mtime.tv_sec - (365*8+2)*24*60*60); >+ asfs_bstore(sb, dir_bh); >+ >+ unlock_super(sb); >+ >+ asfs_brelse(bh); >+ asfs_brelse(dir_bh); >+ >+ return 0; >+} >+ >+int asfs_rmdir(struct inode *dir, struct dentry *dentry) >+{ >+ struct inode *inode = dentry->d_inode; >+ int error; >+ struct super_block *sb = dir->i_sb; >+ struct buffer_head *bh, *dir_bh; >+ struct fsObject *dir_obj, *obj; >+ >+ asfs_debug("ASFS: " __FUNCTION__ "\n"); >+ >+ if (ASFS_I(inode)->firstblock != 0) >+ return -ENOTEMPTY; >+ >+ lock_super(sb); >+ >+ if ((error = readobject(sb, inode->i_ino, &bh, &obj)) != 0) { >+ unlock_super(sb); >+ return error; >+ } >+ >+ if ((error = deleteobject(sb, bh, obj)) != 0) >+ { >+ unlock_super(sb); >+ asfs_brelse(bh); >+ return error; >+ } >+ >+ asfs_brelse(bh); >+ >+ /* directory data could change after removing the object... */ >+ >+ if ((error = readobject(sb, dir->i_ino, &dir_bh, &dir_obj)) != 0) { >+ unlock_super(sb); >+ return error; >+ } >+ >+ ASFS_I(dir)->firstblock = be32_to_cpu(dir_obj->object.dir.firstdirblock); >+ ASFS_I(dir)->modified = 1; >+ dir->i_mtime = dir->i_ctime = inode->i_mtime; >+ dir_obj->datemodified = cpu_to_be32(inode->i_mtime.tv_sec - (365*8+2)*24*60*60); >+ asfs_bstore(sb, dir_bh); >+ >+ dec_count(inode); >+ >+ unlock_super(sb); >+ >+ asfs_brelse(dir_bh); >+ >+ return 0; >+} >+ >+int asfs_delete(struct inode *dir, struct dentry *dentry) >+{ >+ struct inode *inode = dentry->d_inode; >+ int error; >+ struct super_block *sb = dir->i_sb; >+ struct buffer_head *bh, *dir_bh; >+ struct fsObject *dir_obj, *obj; >+ >+ asfs_debug("ASFS: " __FUNCTION__ "\n"); >+ >+ lock_super(sb); >+ >+ if ((error = readobject(sb, inode->i_ino, &bh, &obj)) != 0) { >+ unlock_super(sb); >+ return error; >+ } >+ >+ if ((error = deleteobject(sb, bh, obj)) != 0) { >+ asfs_brelse(bh); >+ unlock_super(sb); >+ return error; >+ } >+ >+ asfs_brelse(bh); >+ >+ if ((error = readobject(sb, dir->i_ino, &dir_bh, &dir_obj)) != 0) { >+ unlock_super(sb); >+ return error; >+ } >+ >+ ASFS_I(dir)->firstblock = be32_to_cpu(dir_obj->object.dir.firstdirblock); >+ ASFS_I(dir)->modified = 1; >+ dir->i_mtime = dir->i_ctime = inode->i_mtime; >+ dir_obj->datemodified = cpu_to_be32(inode->i_mtime.tv_sec - (365*8+2)*24*60*60); >+ asfs_bstore(sb, dir_bh); >+ >+ dec_count(inode); >+ >+ unlock_super(sb); >+ >+ asfs_brelse(dir_bh); >+ >+ return 0; >+} >+ >+int asfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) >+{ >+ struct super_block *sb = old_dir->i_sb; >+ struct buffer_head *src_bh, *old_bh, *new_bh; >+ int error; >+ struct fsObject *src_obj, *old_obj, *new_obj; >+ >+ asfs_debug("ASFS: rename (old=%u,\"%*s\" to new=%u,\"%*s\")\n", >+ (u32)old_dir->i_ino, (int)old_dentry->d_name.len, old_dentry->d_name.name, >+ (u32)new_dir->i_ino, (int)new_dentry->d_name.len, new_dentry->d_name.name); >+ >+ /* Unlink destination if it already exists */ >+ if (new_dentry->d_inode) >+ if ((error = asfs_delete(new_dir, new_dentry)) != 0) >+ return error; >+ >+ lock_super(sb); >+ >+ if ((error = readobject(sb, old_dentry->d_inode->i_ino, &src_bh, &src_obj)) != 0) { >+ unlock_super(sb); >+ return error; >+ } >+ >+ if ((error = readobject(sb, new_dir->i_ino, &new_bh, &new_obj)) != 0) { >+ asfs_brelse(src_bh); >+ unlock_super(sb); >+ return error; >+ } >+ >+ if ((error = renameobject(sb, src_bh, src_obj, new_bh, new_obj, (u8 *) new_dentry->d_name.name)) != 0) { >+ asfs_brelse(src_bh); >+ asfs_brelse(new_bh); >+ unlock_super(sb); >+ return error; >+ } >+ >+ asfs_brelse(src_bh); >+ >+ if ((error = readobject(sb, old_dir->i_ino, &old_bh, &old_obj)) != 0) { >+ asfs_brelse(new_bh); >+ unlock_super(sb); >+ return error; >+ } >+ >+ old_dir->i_mtime = old_dir->i_ctime = new_dir->i_mtime = new_dir->i_ctime = CURRENT_TIME; >+ >+ ASFS_I(old_dir)->firstblock = be32_to_cpu(old_obj->object.dir.firstdirblock); >+ ASFS_I(old_dir)->modified = 1; >+ old_obj->datemodified = cpu_to_be32(old_dir->i_mtime.tv_sec - (365*8+2)*24*60*60); >+ >+ ASFS_I(new_dir)->firstblock = be32_to_cpu(new_obj->object.dir.firstdirblock); >+ ASFS_I(new_dir)->modified = 1; >+ new_obj->datemodified = cpu_to_be32(old_dir->i_mtime.tv_sec - (365*8+2)*24*60*60); >+ >+ asfs_bstore(sb, new_bh); >+ asfs_bstore(sb, old_bh); >+ >+ unlock_super(sb); >+ >+ asfs_brelse(new_bh); >+ asfs_brelse(old_bh); >+ >+ mark_inode_dirty(old_dir); >+ mark_inode_dirty(new_dir); >+ >+ return 0; >+} >+/* >+int asfs_notify_change(struct dentry *dentry, struct iattr *attr) >+{ >+ int error = 0; >+ >+ asfs_debug("ASFS: notify_change(%lu,0x%x)\n",dentry->d_inode->i_ino,attr->ia_valid); >+ >+ return error; >+} >+*/ >+#endif >diff -urN kernel-source-2.6.5/fs/asfs/Makefile kernel-source-2.6.5-powerpc/fs/asfs/Makefile >--- kernel-source-2.6.5/fs/asfs/Makefile 1970-01-01 01:00:00.000000000 +0100 >+++ kernel-source-2.6.5-powerpc/fs/asfs/Makefile 2004-04-12 23:39:01.000000000 +0200 >@@ -0,0 +1,7 @@ >+# >+# Makefile for the linux asfs filesystem routines. >+# >+ >+obj-$(CONFIG_ASFS_FS) += asfs.o >+ >+asfs-objs := adminspace.o bitfuncs.o dir.o extents.o file.o inode.o namei.o nodes.o objects.o super.o symlink.o >diff -urN kernel-source-2.6.5/fs/asfs/namei.c kernel-source-2.6.5-powerpc/fs/asfs/namei.c >--- kernel-source-2.6.5/fs/asfs/namei.c 1970-01-01 01:00:00.000000000 +0100 >+++ kernel-source-2.6.5-powerpc/fs/asfs/namei.c 2004-04-12 23:39:01.000000000 +0200 >@@ -0,0 +1,155 @@ >+/* >+ * >+ * Amiga Smart File System, Linux implementation >+ * version: 1.0beta3 >+ * >+ * Copyright (C) 2003,2004 Marek 'March' Szyprowski <marek@amiga.pl> >+ * >+ * >+ * 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/asfs_fs.h> >+#include <linux/fs.h> >+#include <linux/buffer_head.h> >+#include <linux/vfs.h> >+#include <linux/string.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); >+} >+ >+/* Check if the name is valid for a asfs object. */ >+ >+static 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; >+ >+ 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_upperchar(*name), 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; >+ >+ /* '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_upperchar(*aname++) != asfs_upperchar(*bname++)) >+ 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) >+{ >+ if (casesensitive) { >+ while (*s == *ct && *ct != '\0' && *ct != '/') { >+ s++; >+ ct++; >+ } >+ } else { >+ while (asfs_upperchar(*s) == asfs_upperchar(*ct) && *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; >+} >+ >diff -urN kernel-source-2.6.5/fs/asfs/nodes.c kernel-source-2.6.5-powerpc/fs/asfs/nodes.c >--- kernel-source-2.6.5/fs/asfs/nodes.c 1970-01-01 01:00:00.000000000 +0100 >+++ kernel-source-2.6.5-powerpc/fs/asfs/nodes.c 2004-04-12 23:39:01.000000000 +0200 >@@ -0,0 +1,455 @@ >+/* >+ * >+ * Amiga Smart File System, Linux implementation >+ * version: 1.0beta3 >+ * >+ * 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/asfs_fs.h> >+#include <linux/fs.h> >+#include <linux/buffer_head.h> >+#include <linux/vfs.h> >+ >+#include <asm/byteorder.h> >+ >+/* Finds a specific node by number. */ >+int 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 = 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 = 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 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 = 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 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 = getnode(sb, objectnode, &bh, &on)) == 0) >+ errorcode = internaldeletenode(sb, bh, (struct fsNode *) on); >+ >+ asfs_brelse(bh); >+ return (errorcode); >+} >+ >+#endif >diff -urN kernel-source-2.6.5/fs/asfs/objects.c kernel-source-2.6.5-powerpc/fs/asfs/objects.c >--- kernel-source-2.6.5/fs/asfs/objects.c 1970-01-01 01:00:00.000000000 +0100 >+++ kernel-source-2.6.5-powerpc/fs/asfs/objects.c 2004-04-12 23:39:01.000000000 +0200 >@@ -0,0 +1,765 @@ >+/* >+ * >+ * Amiga Smart File System, Linux implementation >+ * version: 1.0beta3 >+ * >+ * 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/asfs_fs.h> >+#include <linux/fs.h> >+#include <linux/buffer_head.h> >+#include <linux/vfs.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 *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) == 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 >+ >+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 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 = 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 = 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 = freeadminspace(sb, be32_to_cpu(oc->bheader.ownblock))) != 0) >+ return (errorcode); >+ >+ return (0); >+} >+ >+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; >+ struct buffer_head *block; >+ >+ asfs_debug("dehashobject: Delinking object %d (=ObjectNode) from hashchain. Parentnode = %d\n", objectnode, parentobjectnode); >+ >+ if ((errorcode = 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 = 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 = 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. */ >+ >+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 = deletenode(sb, objectnode); >+ } >+ >+ return (errorcode); >+} >+ >+ /* This function deletes the specified object. */ >+int 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 = freeadminspace(sb, extentbnode); >+ } else if ((bits & OTYPE_DIR) != 0) { >+ asfs_debug("deleteobject: Object is a directory!\n"); >+ errorcode = freeadminspace(sb, hashblckno); >+ } else { >+ asfs_debug("deleteobject: Object is a file\n"); >+ if (extentbnode != 0) >+ errorcode = 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 = 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 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 = getnode(sb, o2->objectnode, &node_bh, &on); >+ else { >+ if ((errorcode = 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 = 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 = 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 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 = 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 = 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 = 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 = 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 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 = 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 (readobject(sb, oldparentnode, &bh1, &o1) == 0) { >+ struct buffer_head *bh2 = bh1; >+ if (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 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 = 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 = 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 = 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 = 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 = deletebnode(sb, ebh, ekey)) != 0) { >+ asfs_brelse(ebh); >+ return errorcode; >+ } >+ } >+ asfs_brelse(ebh); >+ >+ return 0; >+} >+#endif >diff -urN kernel-source-2.6.5/fs/asfs/super.c kernel-source-2.6.5-powerpc/fs/asfs/super.c >--- kernel-source-2.6.5/fs/asfs/super.c 1970-01-01 01:00:00.000000000 +0100 >+++ kernel-source-2.6.5-powerpc/fs/asfs/super.c 2004-04-12 23:39:01.000000000 +0200 >@@ -0,0 +1,502 @@ >+/* >+ * >+ * Amiga Smart File System, Linux implementation >+ * >+ * version: 1.0beta4 (12.04.2004) for 2.6.x kernel >+ * >+ * Copyright (C) 2003,2004 Marek 'March' Szyprowski <marek@amiga.pl> >+ * >+ * >+ * Thanks to Marcin Kurek (Morgoth/Dreamolers-CAPS) for help and parts >+ * of original amiga version of SmartFilesystem source code. >+ * >+ * SmartFilesystem is copyrighted (C) 2003 by: John Hendrikx, >+ * Ralph Schmidt, Emmanuel Lesueur, David Gerber and Marcin Kurek >+ * >+ * >+ * ASFS is based on the Amiga FFS filesystem for Linux >+ * Copyright (C) 1993 Ray Burr >+ * Copyright (C) 1996 Hans-Joachim Widmaier >+ * >+ * Earlier versions were based on the Linux implementation of >+ * the ROMFS file system >+ * Copyright (C) 1997-1999 Janos Farkas <chexum@shadow.banki.hu> >+ * >+ * ASFS used some parts of the smbfs filesystem: >+ * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke >+ * Copyright (C) 1997 by Volker Lendecke >+ * >+ * and parts of the Minix filesystem additionally >+ * Copyright (C) 1991, 1992 Linus Torvalds >+ * Copyright (C) 1996 Gertjan van Wingerde >+ * >+ * >+ * 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. >+ * >+ * >+ * History: >+ * >+ * v1.0beta4 (12.04.2004) >+ * - removed dummy asfs_notify_change (this fixes major bug introduced >+ * in 1.0beta3 - file size wasn't written to disk) until it will >+ * be implemented completely >+ * >+ * v1.0beta3 (22.03.2004) - still beta >+ * - updated for 2.6.x kernels VFS changes >+ * - code clean-up >+ * - added dummy asfs_notify_change (chmod now returns no errors) >+ * - added symlinks write support >+ * - fixed: ASFS_SB(sb)->flags was always zero >+ * >+ * v1.0beta2 (11.01.2004) - special version for Pegasos][ kernel >+ * - separated read and write functions, can be compiled also >+ * as read-only fs >+ * v1.0beta1 (02.12.2003) - first public beta with write support >+ * - added dentry hashing/comparing routines >+ * - code clean-up >+ * >+ * v1.0aplha4 (30.11.2003) - preparing for first public beta >+ * - fixed some problems with renaming/moving files >+ * - fixed two major bugs, which didn't occur when fs was mounted >+ * on loopback device (newly allocated blocks were not written to >+ * disk and state bits were not set correctly on newly mapped file >+ * blocks) >+ * - fixed many small bugs in io code (some buffers were not freed) >+ * - added/modified sb locks in asfs_lookup and asfs_getblock >+ * - fixed serious bug in file block allocation routines >+ * v1.0aplha3 (23.11.2003) >+ * - added (hopefully) all byteswap code, should now work again on >+ * little-endian systems (also with write support!) >+ * - updated documentation >+ * v1.0alpha2 (13.11.2003) >+ * - now alocates file blocks in chunks during one request >+ * - fixed some dead-locks, other fixes >+ * v1.0alpha (02.11.2003) - first working version with full write support >+ * - too much to list it here ;) >+ * >+ * ... (working on write support) >+ * >+ * v0.7 (12.10.2003) - internal realase >+ * - added asfs_breadcheck, modified asfs_get_node, asfs_search_BTree, >+ * no more from_be32/16 macros, other... >+ * - code splitted into several files >+ * >+ * v0.6 (04.09.2003) - final read-only version >+ * - added support for HashTables, directory scaning should be >+ * MUCH faster now >+ * - added checking of block IDs before reading any data from block >+ * >+ * v0.5 (19.07.2003) >+ * - added simple but effective extent cache - real speed-up >+ * in reading large files >+ * - added read support for symlinks - based on AFFS symlinks >+ * >+ * v0.4 (10.07.2003) >+ * - third code clean-up (thanks to Roman Zippel for advice) >+ * - now uses generic readpage and readinode routines >+ * >+ * v0.3beta (17.06.2003) >+ * - second code clean-up >+ * >+ * v0.2beta2 (15.06.2003) >+ * - fixed yet another stupid bug - driver can't read root block on little-endian systems >+ * v0.2beta (15.06.2003) >+ * - fixed stupid bug - now files have 'file' flag (S_IFREG) set... >+ * - added mount options to set uid, gid and mode of files and dirs >+ * - made hidden files & dirs really hidden (= not listed in directories) >+ * - code clean-up >+ * >+ * v0.1beta (11.06.2003) >+ * - after many kernel crashes, finally got it! >+ * - first working read-only filesystem driver >+ * >+ */ >+ >+/* todo: >+ * - clean-up the code >+ * - remove bugs >+ * - add missing features (maybe safe-delete, other...) >+ * - create other fs tools like mkfs.asfs and fsck.asfs, some data-recovery tools >+ */ >+ >+#include <linux/module.h> >+#include <linux/types.h> >+#include <linux/errno.h> >+#include <linux/slab.h> >+#include <linux/asfs_fs.h> >+#include <linux/fs.h> >+#include <linux/init.h> >+#include <linux/smp_lock.h> >+#include <linux/buffer_head.h> >+#include <linux/vfs.h> >+#include <linux/string.h> >+ >+#include <asm/byteorder.h> >+#include <asm/uaccess.h> >+ >+u32 asfs_calcchecksum(void *block, u32 blocksize) >+{ >+ u32 *data = block, checksum = 1; >+ while (blocksize > 0) { >+ checksum += be32_to_cpu(*data++); >+ blocksize -= 4; >+ } >+ checksum -= be32_to_cpu(((struct fsBlockHeader *)block)->checksum); >+ return -checksum; >+} >+ >+static struct super_operations asfs_ops = { >+ .alloc_inode = asfs_alloc_inode, >+ .destroy_inode = asfs_destroy_inode, >+ .put_super = asfs_put_super, >+ .statfs = asfs_statfs, >+#ifdef CONFIG_ASFS_RW >+ .remount_fs = asfs_remount, >+#endif >+}; >+ >+extern struct dentry_operations asfs_dentry_operations; >+ >+static int asfs_parse_options(char *options, struct super_block *sb) >+{ >+ char *this_char, *value, *optn; >+ int f; >+ >+ if (!options) >+ return 1; >+ while ((this_char = strsep(&options, ",")) != NULL) { >+ if (!*this_char) >+ continue; >+ f = 0; >+ if ((value = strchr(this_char,'=')) != NULL) >+ *value++ = 0; >+ if ((optn = "lowercasevol") && !strcmp(this_char, optn)) { >+ if (value) >+ goto out_inv_arg; >+ ASFS_SB(sb)->flags |= ASFS_VOL_LOWERCASE; >+ } else if ((f = !strcmp(this_char,"setuid")) || !strcmp(this_char,"setgid")) { >+ if (value) { >+ if (!*value) { >+ printk("ASFS: Argument for set[ug]id option missing\n"); >+ return 0; >+ } else { >+ (f ? ASFS_SB(sb)->uid : ASFS_SB(sb)->gid) = simple_strtoul(value,&value,0); >+ if (*value) { >+ printk("ASFS: Bad set[ug]id argument\n"); >+ return 0; >+ } >+ } >+ } >+ } else if (!strcmp(this_char,"mode")) { >+ optn = "mode"; >+ if (!value || !*value) >+ goto out_no_arg; >+ ASFS_SB(sb)->mode = simple_strtoul(value,&value,8) & 0777; >+ if (*value) >+ return 0; >+ } else if (!strcmp(this_char,"prefix")) { >+ optn = "prefix"; >+ if (!value || !*value) >+ goto out_no_arg; >+ if (ASFS_SB(sb)->prefix) >+ kfree(ASFS_SB(sb)->prefix); >+ ASFS_SB(sb)->prefix = kmalloc(strlen(value) + 1,GFP_KERNEL); >+ if (!ASFS_SB(sb)->prefix) >+ return 0; >+ strcpy(ASFS_SB(sb)->prefix,value); >+ } else if (!strcmp(this_char,"volume")) { >+ optn = "volume"; >+ if (!value || !*value) >+ goto out_no_arg; >+ if (ASFS_SB(sb)->root_volume) >+ kfree(ASFS_SB(sb)->root_volume); >+ ASFS_SB(sb)->root_volume = kmalloc(strlen(value) + 1,GFP_KERNEL); >+ if (!ASFS_SB(sb)->root_volume) >+ return 0; >+ strcpy(ASFS_SB(sb)->root_volume,value); >+ } else { >+ printk("ASFS: Unrecognized mount option %s\n", this_char); >+ return 0; >+ } >+ } >+ return 1; >+ >+out_no_arg: >+ printk("ASFS: The %s option requires an argument\n", optn); >+ return 0; >+out_inv_arg: >+ printk("ASFS: Option %s does not take an argument\n", optn); >+ return 0; >+} >+ >+static int asfs_fill_super(struct super_block *sb, void *data, int silent) >+{ >+ struct asfs_sb_info *sbi; >+ struct buffer_head *bh; >+ struct fsRootBlock *rootblock; >+ >+ sbi = kmalloc(sizeof(struct asfs_sb_info), GFP_KERNEL); >+ if (!sbi) >+ return -ENOMEM; >+ sb->s_fs_info = sbi; >+ >+ /* Fill in defaults */ >+ ASFS_SB(sb)->uid = ASFS_DEFAULT_UID; >+ ASFS_SB(sb)->gid = ASFS_DEFAULT_GID; >+ ASFS_SB(sb)->mode = ASFS_DEFAULT_MODE; >+ ASFS_SB(sb)->prefix = NULL; >+ ASFS_SB(sb)->root_volume = NULL; >+ ASFS_SB(sb)->flags = 0; >+ >+ if (!asfs_parse_options(data, sb)) { >+ printk(KERN_ERR "ASFS: Error parsing options\n"); >+ return -EINVAL; >+ } >+ >+ if (!sb_set_blocksize(sb, 512)) >+ return -EINVAL; >+ sb->s_maxbytes = 0x8FFFFFFE; >+ >+ bh = sb_bread(sb, 0); >+ if (!bh) { >+ printk(KERN_ERR "ASFS: unable to read superblock\n"); >+ goto outnobh; >+ } >+ >+ rootblock = (struct fsRootBlock *)bh->b_data; >+ >+ if (be32_to_cpu(rootblock->bheader.id) == ASFS_ROOTID && >+ be16_to_cpu(rootblock->version) == ASFS_STRUCTURE_VERISON) { >+ >+ sb->s_blocksize = be32_to_cpu(rootblock->blocksize); >+ ASFS_SB(sb)->totalblocks = be32_to_cpu(rootblock->totalblocks); >+ ASFS_SB(sb)->rootobjectcontainer = be32_to_cpu(rootblock->rootobjectcontainer); >+ ASFS_SB(sb)->extentbnoderoot = be32_to_cpu(rootblock->extentbnoderoot); >+ ASFS_SB(sb)->objectnoderoot = be32_to_cpu(rootblock->objectnoderoot); >+ ASFS_SB(sb)->flags |= 0xff & rootblock->bits; >+#ifdef CONFIG_ASFS_RW >+ ASFS_SB(sb)->adminspacecontainer = be32_to_cpu(rootblock->adminspacecontainer); >+ ASFS_SB(sb)->bitmapbase = be32_to_cpu(rootblock->bitmapbase); >+ ASFS_SB(sb)->blocks_inbitmap = (sb->s_blocksize - sizeof(struct fsBitmap))<<3; /* must be a multiple of 32 !! */ >+ ASFS_SB(sb)->blocks_bitmap = (ASFS_SB(sb)->totalblocks + ASFS_SB(sb)->blocks_inbitmap - 1) / ASFS_SB(sb)->blocks_inbitmap; >+ ASFS_SB(sb)->block_rovingblockptr = 0; >+#endif >+ asfs_brelse(bh); >+ >+ if (!sb_set_blocksize(sb, sb->s_blocksize)) { >+ printk(KERN_ERR "ASFS: Found Amiga SFS RootBlock on dev %s, but blocksize %ld is not supported!\n", \ >+ sb->s_id, sb->s_blocksize); >+ return -EINVAL; >+ } >+ >+ bh = sb_bread(sb, 0); >+ if (!bh) { >+ printk(KERN_ERR "ASFS: unable to read superblock\n"); >+ goto out; >+ } >+ rootblock = (struct fsRootBlock *)bh->b_data; >+ >+ if (asfs_check_block((void *)rootblock, sb->s_blocksize, 0, ASFS_ROOTID)) { >+#ifdef CONFIG_ASFS_RW >+ struct buffer_head *tmpbh; >+ if ((tmpbh = asfs_breadcheck(sb, ASFS_SB(sb)->rootobjectcontainer, ASFS_OBJECTCONTAINER_ID))) { >+ struct fsRootInfo *ri = (struct fsRootInfo *)((u8 *)tmpbh->b_data + sb->s_blocksize - sizeof(struct fsRootInfo)); >+ ASFS_SB(sb)->freeblocks = be32_to_cpu(ri->freeblocks); >+ asfs_brelse(tmpbh); >+ } else >+ ASFS_SB(sb)->freeblocks = 0; >+ >+ if ((tmpbh = asfs_breadcheck(sb, ASFS_SB(sb)->rootobjectcontainer+2, ASFS_TRANSACTIONFAILURE_ID))) { >+ printk(KERN_NOTICE "VFS: Found Amiga SFS RootBlock on dev %s, but it has unfinished transaction. Mounting read-only.\n", sb->s_id); >+ ASFS_SB(sb)->flags |= ASFS_READONLY; >+ asfs_brelse(tmpbh); >+ } >+ >+ if ((tmpbh = asfs_breadcheck(sb, ASFS_SB(sb)->totalblocks-1, ASFS_ROOTID)) == NULL) { >+ printk(KERN_NOTICE "VFS: Found Amiga SFS RootBlock on dev %s, but there is no second RootBlock! Mounting read-only.\n", sb->s_id); >+ ASFS_SB(sb)->flags |= ASFS_READONLY; >+ asfs_brelse(tmpbh); >+ } >+ if (!(ASFS_SB(sb)->flags &= ASFS_READONLY)) >+ printk(KERN_NOTICE "VFS: Found Amiga SFS RootBlock on dev %s.\n", sb->s_id); >+#else >+ ASFS_SB(sb)->freeblocks = 0; >+ ASFS_SB(sb)->flags |= ASFS_READONLY; >+ printk(KERN_NOTICE "VFS: Found Amiga SFS RootBlock on dev %s.\n", sb->s_id); >+#endif >+ } else { >+ if (!silent) >+ printk(KERN_ERR "VFS: Found Amiga SFS RootBlock on dev %s, but it has checksum error!\n", \ >+ sb->s_id); >+ goto out; >+ } >+ } else { >+ if (!silent) >+ printk(KERN_ERR "VFS: Can't find a valid Amiga SFS filesystem on dev %s.\n", \ >+ sb->s_id); >+ goto out; >+ } >+ >+ asfs_brelse(bh); >+ >+ sb->s_magic = ASFS_MAGIC; >+ sb->s_flags |= MS_NODEV | MS_NOSUID; >+ if (ASFS_SB(sb)->flags & ASFS_READONLY) >+ sb->s_flags |= MS_RDONLY; >+ sb->s_op = &asfs_ops; >+ sb->s_root = d_alloc_root(asfs_get_root_inode(sb)); >+ if (!sb->s_root) >+ goto outnobh; >+ sb->s_root->d_op = &asfs_dentry_operations; >+ >+ /* Ehrhm; sorry.. :) */ >+ if (0) { >+out: >+ asfs_brelse(bh); >+outnobh: >+ return -EINVAL; >+ } >+ return 0; >+} >+ >+#ifdef CONFIG_ASFS_RW >+int asfs_remount(struct super_block *sb, int *flags, char *data) >+{ >+ asfs_debug("ASFS: remount (flags=0x%x, opts=\"%s\")\n",*flags,data); >+ >+ if (!asfs_parse_options(data,sb)) >+ return -EINVAL; >+ >+ if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) >+ return 0; >+ >+ if (*flags & MS_RDONLY) { >+ sb->s_flags |= MS_RDONLY; >+ } else if (!(ASFS_SB(sb)->flags & ASFS_READONLY)) { >+ sb->s_flags &= ~MS_RDONLY; >+ } else { >+ printk("VFS: Can't remount Amiga SFS on dev %s read/write because of errors.", sb->s_id); >+ return -EINVAL; >+ } >+ return 0; >+} >+#endif >+ >+void asfs_put_super(struct super_block *sb) >+{ >+ struct asfs_sb_info *sbi = ASFS_SB(sb); >+ >+ if (ASFS_SB(sb)->prefix) >+ kfree(ASFS_SB(sb)->prefix); >+ >+ kfree(sbi); >+ sb->s_fs_info = NULL; >+ return; >+} >+ >+/* That's simple too. */ >+ >+int asfs_statfs(struct super_block *sb, struct kstatfs *buf) >+{ >+ buf->f_type = ASFS_MAGIC; >+ buf->f_bsize = sb->s_blocksize; >+ buf->f_bfree = buf->f_bavail = ASFS_SB(sb)->freeblocks; >+ buf->f_blocks = ASFS_SB(sb)->totalblocks; >+ buf->f_namelen = ASFS_MAXFN; >+ return 0; >+} >+ >+/* --- new in 2.6.x --- */ >+static kmem_cache_t * asfs_inode_cachep; >+ >+struct inode *asfs_alloc_inode(struct super_block *sb) >+{ >+ struct asfs_inode_info *ei; >+ ei = (struct asfs_inode_info *)kmem_cache_alloc(asfs_inode_cachep, SLAB_KERNEL); >+ if (!ei) >+ return NULL; >+ return &ei->vfs_inode; >+} >+ >+void asfs_destroy_inode(struct inode *inode) >+{ >+ kmem_cache_free(asfs_inode_cachep, ASFS_I(inode)); >+} >+ >+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) >+{ >+ struct asfs_inode_info *ei = (struct asfs_inode_info *) foo; >+ >+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == >+ SLAB_CTOR_CONSTRUCTOR) { >+ inode_init_once(&ei->vfs_inode); >+ } >+} >+ >+static int init_inodecache(void) >+{ >+ asfs_inode_cachep = kmem_cache_create("asfs_inode_cache", >+ sizeof(struct asfs_inode_info), >+ 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, >+ init_once, NULL); >+ if (asfs_inode_cachep == NULL) >+ return -ENOMEM; >+ return 0; >+} >+ >+static void destroy_inodecache(void) >+{ >+ if (kmem_cache_destroy(asfs_inode_cachep)) >+ printk(KERN_INFO "asfs_inode_cache: not all structures were freed\n"); >+} >+ >+static struct super_block *asfs_get_sb(struct file_system_type *fs_type, >+ int flags, const char *dev_name, void *data) >+{ >+ return get_sb_bdev(fs_type, flags, dev_name, data, asfs_fill_super); >+} >+ >+static struct file_system_type asfs_fs_type = { >+ .owner = THIS_MODULE, >+ .name = "asfs", >+ .get_sb = asfs_get_sb, >+ .kill_sb = kill_block_super, >+ .fs_flags = FS_REQUIRES_DEV, >+}; >+ >+static int __init init_asfs_fs(void) >+{ >+ int err = init_inodecache(); >+ if (err) >+ goto out1; >+ err = register_filesystem(&asfs_fs_type); >+ if (err) >+ goto out; >+ return 0; >+out: >+ destroy_inodecache(); >+out1: >+ return err; >+} >+ >+static void __exit exit_asfs_fs(void) >+{ >+ unregister_filesystem(&asfs_fs_type); >+ destroy_inodecache(); >+} >+ >+/* Yes, works even as a module... :) */ >+ >+#ifdef CONFIG_ASFS_RW >+MODULE_DESCRIPTION("Amiga Smart File System (read/write) support for Linux kernel 2.6.x v1.0beta4 (12.04.2004)"); >+#else >+MODULE_DESCRIPTION("Amiga Smart File System (read-only) support for Linux kernel 2.6.x v1.0beta4 (12.04.2004)"); >+#endif >+MODULE_LICENSE("GPL"); >+MODULE_AUTHOR("Marek Szyprowski <marek@amiga.pl>"); >+ >+module_init(init_asfs_fs) >+module_exit(exit_asfs_fs) >diff -urN kernel-source-2.6.5/fs/asfs/symlink.c kernel-source-2.6.5-powerpc/fs/asfs/symlink.c >--- kernel-source-2.6.5/fs/asfs/symlink.c 1970-01-01 01:00:00.000000000 +0100 >+++ kernel-source-2.6.5-powerpc/fs/asfs/symlink.c 2004-04-12 23:39:01.000000000 +0200 >@@ -0,0 +1,227 @@ >+/* >+ * >+ * Amiga Smart File System, Linux implementation >+ * version: 1.0beta3 >+ * >+ * Copyright (C) 2003,2004 Marek 'March' Szyprowski <marek@amiga.pl> >+ * >+ * >+ * 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/asfs_fs.h> >+#include <linux/fs.h> >+#include <linux/buffer_head.h> >+#include <linux/vfs.h> >+#include <linux/pagemap.h> >+ >+#include <asm/byteorder.h> >+#include <asm/uaccess.h> >+ >+extern struct address_space_operations asfs_symlink_aops; >+ >+int asfs_symlink_readpage(struct file *file, struct page *page) >+{ >+ struct buffer_head *bh; >+ struct fsSoftLink *slinkcont; >+ struct inode *inode = page->mapping->host; >+ struct super_block *sb = inode->i_sb; >+ char *link = kmap(page); >+ int i = 0, j = 0; >+ char c, lc = 0, *prefix, *lf, *p; >+ >+ if (!(bh = asfs_breadcheck(sb, ASFS_I(inode)->firstblock, ASFS_SOFTLINK_ID))) { >+ SetPageError(page); >+ kunmap(page); >+ unlock_page(page); >+ return -EIO; >+ } >+ slinkcont = (struct fsSoftLink *) bh->b_data; >+ >+ lf = slinkcont->string; >+ prefix = ASFS_SB(sb)->prefix ? ASFS_SB(sb)->prefix : "/"; >+ >+ if ((p = strchr(lf,':'))) { /* Handle assign or volume name */ >+ if (ASFS_SB(sb)->root_volume && >+ strncmp(lf, ASFS_SB(sb)->root_volume, strlen(ASFS_SB(sb)->root_volume)) == 0) { >+ /* global root volume name found */ >+ link[i++] = '/'; >+ lf = p+1; >+ } else { >+ /* adding volume prefix */ >+ while (i < 1023 && (c = prefix[i])) >+ link[i++] = c; >+ if (ASFS_SB(sb)->flags & ASFS_VOL_LOWERCASE) { >+ while (i < 1023 && lf[j] != ':') >+ link[i++] = asfs_lowerchar(lf[j++]); >+ } else { >+ while (i < 1023 && lf[j] != ':') >+ link[i++] = lf[j++]; >+ } >+ if (i < 1023) >+ link[i++] = '/'; >+ j++; >+ } >+ lc = '/'; >+ } >+ >+ while (i < 1023 && (c = lf[j])) { >+ if (c == '/' && lc == '/' && i < 1020) { /* parent dir */ >+ link[i++] = '.'; >+ link[i++] = '.'; >+ } >+ link[i++] = c; >+ lc = c; >+ j++; >+ } >+ link[i] = '\0'; >+ SetPageUptodate(page); >+ kunmap(page); >+ unlock_page(page); >+ asfs_brelse(bh); >+ return 0; >+} >+ >+#ifdef CONFIG_ASFS_RW >+ >+int asfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) >+{ >+ int error; >+ struct super_block *sb = dir->i_sb; >+ struct inode *inode; >+ struct buffer_head *bh, *dir_bh; >+ struct fsObject obj_data, *dir_obj, *obj; >+ u8 *name = (u8 *) dentry->d_name.name; >+ struct fsSoftLink *slinkcont; >+ char *p; >+ int i, maxlen, pflen; >+ char c, lc; >+ >+ asfs_debug("asfs_symlink %s in dir node %d\n", name, (int)dir->i_ino); >+ >+ sb = dir->i_sb; >+ inode = new_inode(sb); >+ if (!inode) >+ return -ENOMEM; >+ >+ inode->i_mode = S_IFLNK | S_IRWXUGO; >+ inode->i_uid = current->fsuid; >+ inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; >+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; >+ inode->i_blocks = inode->i_blksize = inode->i_size = 0; >+ >+ inode->i_op = &page_symlink_inode_operations; >+ inode->i_mapping->a_ops = &asfs_symlink_aops; >+ >+ memset(&obj_data, 0, sizeof(struct fsObject)); >+ >+ obj_data.protection = cpu_to_be32(FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE); >+ obj_data.datemodified = cpu_to_be32(inode->i_mtime.tv_sec - (365*8+2)*24*60*60); >+ obj_data.bits = OTYPE_LINK; >+ >+ lock_super(sb); >+ >+ if ((error = readobject(sb, dir->i_ino, &dir_bh, &dir_obj)) != 0) { >+ dec_count(inode); >+ unlock_super(sb); >+ return error; >+ } >+ >+ bh = dir_bh; >+ obj = dir_obj; >+ >+ if ((error = createobject(sb, &bh, &obj, &obj_data, name, FALSE)) != 0) { >+ asfs_brelse(dir_bh); >+ dec_count(inode); >+ unlock_super(sb); >+ return error; >+ } >+ >+ inode->i_ino = be32_to_cpu(obj->objectnode); >+ ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data); >+ asfs_bstore(sb, bh); >+ >+ insert_inode_hash(inode); >+ mark_inode_dirty(inode); >+ >+ d_instantiate(dentry, inode); >+ ASFS_I(dir)->firstblock = be32_to_cpu(dir_obj->object.dir.firstdirblock); >+ ASFS_I(dir)->modified = 1; >+ dir->i_mtime = dir->i_ctime = inode->i_mtime; >+ dir_obj->datemodified = cpu_to_be32(inode->i_mtime.tv_sec - (365*8+2)*24*60*60); >+ asfs_bstore(sb, dir_bh); >+ >+ asfs_brelse(dir_bh); >+ asfs_brelse(bh); >+ >+ if (!(bh = asfs_breadcheck(sb, ASFS_I(inode)->firstblock, ASFS_SOFTLINK_ID))) { >+ unlock_super(sb); >+ return -EIO; >+ } >+ slinkcont = (struct fsSoftLink *) bh->b_data; >+ >+ /* translating symlink target path */ >+ >+ maxlen = sb->s_blocksize - sizeof(struct fsSoftLink) - 2; >+ i = 0; >+ p = slinkcont->string; >+ lc = '/'; >+ >+ if (*symname == '/') { >+ while (*symname == '/') >+ symname++; >+ if (ASFS_SB(sb)->prefix && >+ strncmp(symname-1, ASFS_SB(sb)->prefix, (pflen = strlen(ASFS_SB(sb)->prefix))) == 0) { >+ /* found volume prefix, ommiting it */ >+ symname += pflen; >+ while ((c = *symname++) != '/' && c != '\0') { >+ *p++ = c; >+ i++; >+ } >+ *p++ = ':'; >+ } else if (ASFS_SB(sb)->root_volume) { /* adding root volume name */ >+ while (ASFS_SB(sb)->root_volume[i]) >+ *p++ = ASFS_SB(sb)->root_volume[i++]; >+ *p++ = ':'; >+ } else { /* do nothing */ >+ *p++ = '/'; >+ } >+ i++; >+ } >+ >+ while (i < maxlen && (c = *symname++)) { >+ if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') { >+ *p++ = '/'; >+ i++; >+ symname += 2; >+ lc = '/'; >+ } else if (c == '.' && lc == '/' && *symname == '/') { >+ symname++; >+ lc = '/'; >+ } else { >+ *p++ = c; >+ lc = c; >+ i++; >+ } >+ if (lc == '/') >+ while (*symname == '/') >+ symname++; >+ } >+ *p = 0; >+ >+ asfs_bstore(sb, bh); >+ asfs_brelse(bh); >+ >+ unlock_super(sb); >+ >+ return 0; >+} >+ >+#endif >diff -urN kernel-source-2.6.5/fs/Kconfig kernel-source-2.6.5-powerpc/fs/Kconfig >--- kernel-source-2.6.5/fs/Kconfig 2004-04-05 11:49:37.000000000 +0200 >+++ kernel-source-2.6.5-powerpc/fs/Kconfig 2004-04-12 23:39:01.000000000 +0200 >@@ -966,6 +966,40 @@ > To compile this file system support as a module, choose M here: the > module will be called affs. If unsure, say N. > >+config ASFS_FS >+ tristate "Amiga SFS file system support (EXPERIMENTAL)" >+ depends on EXPERIMENTAL >+ help >+ >+ The Amiga Smart FileSystem (SFS) is the file system used on hard >+ disks by Amiga(tm) and MorphOS(tm) systems. Say Y if you want >+ to be able to read files from an Amiga SFS partition on your hard >+ drive. >+ >+ This file system driver is in EXPERIMENTAL state. Use it with care. >+ It MIGHT cause a crash in some circumstances. >+ >+ For more information read <file:Documentation/filesystems/asfs.txt> >+ >+ This file system is also available as a module ( = code which can be >+ inserted in and removed from the running kernel whenever you want). >+ The module is called asfs.o. If you want to compile it as a module, >+ say M here and read <file:Documentation/modules.txt>. >+ >+ If unsure, say N. >+ >+config ASFS_RW >+ bool "Amiga SFS write support (DANGEROUS)" >+ depends on ASFS_FS >+ help >+ >+ If you say Y here, you will be able to write to ASFS file >+ systems as well as read from them. The read-write support in ASFS >+ is in early beta stage. This means that useing it to write files >+ to SFS partitions is DANGEROUS and COULD corrupt the filesystem. >+ >+ If unsure, say N. >+ > config HFS_FS > tristate "Apple Macintosh file system support (EXPERIMENTAL)" > depends on EXPERIMENTAL >diff -urN kernel-source-2.6.5/fs/Makefile kernel-source-2.6.5-powerpc/fs/Makefile >--- kernel-source-2.6.5/fs/Makefile 2004-03-11 03:55:29.000000000 +0100 >+++ kernel-source-2.6.5-powerpc/fs/Makefile 2004-04-12 23:39:01.000000000 +0200 >@@ -81,6 +81,7 @@ > obj-$(CONFIG_JFFS_FS) += jffs/ > obj-$(CONFIG_JFFS2_FS) += jffs2/ > obj-$(CONFIG_AFFS_FS) += affs/ >+obj-$(CONFIG_ASFS_FS) += asfs/ > obj-$(CONFIG_ROMFS_FS) += romfs/ > obj-$(CONFIG_QNX4FS_FS) += qnx4/ > obj-$(CONFIG_AUTOFS_FS) += autofs/ >diff -urN kernel-source-2.6.5/include/linux/asfs_fs.h kernel-source-2.6.5-powerpc/include/linux/asfs_fs.h >--- kernel-source-2.6.5/include/linux/asfs_fs.h 1970-01-01 01:00:00.000000000 +0100 >+++ kernel-source-2.6.5-powerpc/include/linux/asfs_fs.h 2004-04-12 23:39:01.000000000 +0200 >@@ -0,0 +1,455 @@ >+#ifndef __LINUX_ASFS_FS_H >+#define __LINUX_ASFS_FS_H >+ >+#include <linux/types.h> >+#include <asm/byteorder.h> >+ >+#define asfs_debug(fmt,arg...) /* no debug at all */ >+//#define asfs_debug(fmt,arg...) printk(fmt,##arg) /* general debug infos */ >+ >+#if !defined (__BIG_ENDIAN) && !defined (__LITTLE_ENDIAN) >+#error Endianes must be known for ASFS to work. Sorry. >+#endif >+ >+/* some helper macros... */ >+#define ASFS_MAKE_ID(a,b,c,d) (((a)&0xff)<<24|((b)&0xff)<<16|((c)&0xff)<<8|((d)&0xff)) >+ >+/* Amiga SFS block IDs */ >+#define ASFS_ROOTID ASFS_MAKE_ID('S','F','S','\0') >+#define ASFS_OBJECTCONTAINER_ID ASFS_MAKE_ID('O','B','J','C') >+#define ASFS_BNODECONTAINER_ID ASFS_MAKE_ID('B','N','D','C') >+#define ASFS_NODECONTAINER_ID ASFS_MAKE_ID('N','D','C',' ') >+#define ASFS_HASHTABLE_ID ASFS_MAKE_ID('H','T','A','B') >+#define ASFS_SOFTLINK_ID ASFS_MAKE_ID('S','L','N','K') >+#define ASFS_ADMINSPACECONTAINER_ID ASFS_MAKE_ID('A','D','M','C') >+#define ASFS_BITMAP_ID ASFS_MAKE_ID('B','T','M','P') >+#define ASFS_TRANSACTIONFAILURE_ID ASFS_MAKE_ID('T','R','F','A') >+ >+/* Amiga SFS defines and magic values */ >+ >+#define ASFS_MAGIC 0xa0ff >+#define ASFS_MAXFN (105u) >+ >+#define ASFS_DEFAULT_UID 0 >+#define ASFS_DEFAULT_GID 0 >+#define ASFS_DEFAULT_MODE 0644 /* default permission bits for files, dirs have same permission, but with "x" set */ >+ >+#define ASFS_STRUCTURE_VERISON (3) >+#define ASFS_BLCKFACCURACY (5) >+ >+#define ASFS_ROOTBITS_CASESENSITIVE (128) >+#define ASFS_READONLY (512) >+#define ASFS_VOL_LOWERCASE (1024) >+ >+#define ASFS_ROOTNODE (1) >+#define ASFS_RECYCLEDNODE (2) >+ >+#define OTYPE_HIDDEN (1) >+#define OTYPE_HARDLINK (32) >+#define OTYPE_LINK (64) >+#define OTYPE_DIR (128) >+ >+#define MSB_MASK (1ul << 31) >+ >+#define NODE_STRUCT_SIZE (10) /* (sizeof(struct fsObjectNode)) */ >+#define NODECONT_BLOCK_COUNT ((sb->s_blocksize - sizeof(struct fsNodeContainer)) / sizeof(u32)) >+ >+#define ASFS_ALWAYSFREE (16) /* keep this amount of blocks free */ >+ >+#define ASFS_BLOCKCHUNKS (16) /* try to allocate this number of blocks in one request */ >+ >+#ifndef TRUE >+#define TRUE 1 >+#endif >+#ifndef FALSE >+#define FALSE 0 >+#endif >+ >+/* amigados protection bits */ >+ >+#define FIBB_SCRIPT 6 /* program is a script (execute) file */ >+#define FIBB_PURE 5 /* program is reentrant and rexecutable */ >+#define FIBB_ARCHIVE 4 /* cleared whenever file is changed */ >+#define FIBB_READ 3 /* ignored by old filesystem */ >+#define FIBB_WRITE 2 /* ignored by old filesystem */ >+#define FIBB_EXECUTE 1 /* ignored by system, used by Shell */ >+#define FIBB_DELETE 0 /* prevent file from being deleted */ >+ >+#define FIBF_SCRIPT (1<<FIBB_SCRIPT) >+#define FIBF_PURE (1<<FIBB_PURE) >+#define FIBF_ARCHIVE (1<<FIBB_ARCHIVE) >+#define FIBF_READ (1<<FIBB_READ) >+#define FIBF_WRITE (1<<FIBB_WRITE) >+#define FIBF_EXECUTE (1<<FIBB_EXECUTE) >+#define FIBF_DELETE (1<<FIBB_DELETE) >+ >+/* name hashing macro */ >+ >+#define HASHCHAIN(x) (u16)(x % (u16)(((sb->s_blocksize) - sizeof(struct fsHashTable))>>2)) >+ >+/* Each block has its own header with checksum and id, its called fsBlockHeader */ >+ >+struct fsBlockHeader { >+ u32 id; /* 4 character id string of this block */ >+ u32 checksum; /* The checksum */ >+ u32 ownblock; /* The blocknumber of the block this block is stored at */ >+}; >+ >+/* On-disk "super block", called fsRootBlock */ >+ >+struct fsRootBlock { >+ struct fsBlockHeader bheader; >+ >+ u16 version; /* Version number of the filesystem block structure */ >+ u16 sequencenumber; /* The Root with the highest sequencenumber is valid */ >+ >+ u32 datecreated; /* Creation date (when first formatted). Cannot be changed. */ >+ u8 bits; /* various settings, see defines below. */ >+ u8 pad1; >+ u16 pad2; >+ >+ u32 reserved1[2]; >+ >+ u32 firstbyteh; /* The first byte of our partition from the start of the */ >+ u32 firstbyte; /* disk. firstbyteh = upper 32 bits, firstbyte = lower 32 bits. */ >+ >+ u32 lastbyteh; /* The last byte of our partition, excluding this one. */ >+ u32 lastbyte; >+ >+ u32 totalblocks; /* size of this partition in blocks */ >+ u32 blocksize; /* blocksize used */ >+ >+ u32 reserved2[2]; >+ u32 reserved3[8]; >+ >+ u32 bitmapbase; /* location of the bitmap */ >+ u32 adminspacecontainer; /* location of first adminspace container */ >+ u32 rootobjectcontainer; /* location of the root objectcontainer */ >+ u32 extentbnoderoot; /* location of the root of the extentbnode B-tree */ >+ u32 objectnoderoot; /* location of the root of the objectnode tree */ >+ >+ u32 reserved4[3]; >+}; >+ >+/* On disk inode, called fsObject */ >+ >+struct fsObject { >+ u16 owneruid; >+ u16 ownergid; >+ u32 objectnode; >+ u32 protection; >+ >+ union { >+ struct { >+ u32 data; >+ u32 size; >+ } file; >+ >+ struct { >+ u32 hashtable; /* for directories & root, 0 means no hashblock */ >+ u32 firstdirblock; >+ } dir; >+ } object; >+ >+ u32 datemodified; >+ u8 bits; >+ >+ u8 name[0]; >+ u8 comment[0]; >+}; >+ >+/* On disk block containging a number of fsObjects */ >+ >+struct fsObjectContainer { >+ struct fsBlockHeader bheader; >+ >+ u32 parent; >+ u32 next; >+ u32 previous; /* 0 for the first block in the directory chain */ >+ >+ struct fsObject object[0]; >+}; >+ >+/* BTree structures, used to collect file data position on disk */ >+ >+struct fsExtentBNode { >+ u32 key; /* data! */ >+ u32 next; >+ u32 prev; >+ u16 blocks; /* The size in blocks of the region this Extent controls */ >+}; >+ >+struct BNode { >+ u32 key; >+ u32 data; >+}; >+ >+struct BTreeContainer { >+ u16 nodecount; >+ u8 isleaf; >+ u8 nodesize; /* Must be a multiple of 2 */ >+ >+ struct BNode bnode[0]; >+}; >+ >+/* On disk block with BTreeContainer */ >+ >+struct fsBNodeContainer { >+ struct fsBlockHeader bheader; >+ struct BTreeContainer btc; >+}; >+ >+/* On disk block with soft link data */ >+ >+struct fsSoftLink { >+ struct fsBlockHeader bheader; >+ u32 parent; >+ u32 next; >+ u32 previous; >+ u8 string[0]; >+}; >+ >+/* On disk block with hashtable data */ >+ >+struct fsHashTable { >+ struct fsBlockHeader bheader; >+ u32 parent; >+ u32 hashentry[0]; >+}; >+ >+/* On disk block with node index and some helper structures */ >+ >+struct fsNodeContainer { >+ struct fsBlockHeader bheader; >+ u32 nodenumber; >+ u32 nodes; >+ u32 node[0]; >+}; >+ >+struct fsNode { >+ u32 data; >+}; >+ >+struct fsObjectNode { >+ struct fsNode node; >+ u32 next; >+ u16 hash16; >+} __attribute__ ((packed)); >+ >+/* Some adminspace and bitmap block structures */ >+ >+struct fsAdminSpace { >+ u32 space; >+ u32 bits; >+/* Set bits are used blocks, bit 31 is the first block in the AdminSpace. */ >+}; >+ >+struct fsAdminSpaceContainer { >+ struct fsBlockHeader bheader; >+ >+ u32 next; >+ u32 previous; >+ >+ u8 bits; >+ u8 pad1; >+ u16 pad2; >+ >+ struct fsAdminSpace adminspace[0]; >+}; >+ >+struct fsBitmap { >+ struct fsBlockHeader bheader; >+ >+ u32 bitmap[0]; >+ >+/* Bits are 1 if the block is free, and 0 if full. >+ Bitmap must consist of an integral number of longwords. */ >+}; >+ >+/* The fsRootInfo structure has all kinds of information about the format >+ of the disk. */ >+ >+struct fsRootInfo { >+ u32 deletedblocks; /* Amount in blocks which deleted files consume. */ >+ u32 deletedfiles; /* Number of deleted files in recycled. */ >+ u32 freeblocks; /* Cached number of free blocks on disk. */ >+ >+ u32 datecreated; >+ >+ u32 lastallocatedblock; /* Block which was most recently allocated */ >+ u32 lastallocatedadminspace; /* AdminSpaceContainer which most recently was used to allocate a block */ >+ u32 lastallocatedextentnode; /* ExtentNode which was most recently created */ >+ u32 lastallocatedobjectnode; /* ObjectNode which was most recently created */ >+ >+ u32 rovingpointer; >+}; >+ >+ >+#ifdef __KERNEL__ >+ >+#include <linux/fs.h> >+#include <linux/buffer_head.h> >+ >+#include <linux/asfs_fs_i.h> >+#include <linux/asfs_fs_sb.h> >+ >+/* io inline code */ >+ >+u32 asfs_calcchecksum(void *block, u32 blocksize); >+ >+static inline int >+asfs_check_block(struct fsBlockHeader *block, u32 blocksize, u32 n, u32 id) >+{ >+ if (asfs_calcchecksum(block, blocksize) == >+ be32_to_cpu(((struct fsBlockHeader *) block)->checksum) && >+ n == be32_to_cpu(((struct fsBlockHeader *) block)->ownblock) && >+ id == be32_to_cpu(((struct fsBlockHeader *) block)->id)) >+ return 1; >+ return 0; >+} >+ >+/* get fs structure from block and do some checks... */ >+static inline struct buffer_head * >+asfs_breadcheck(struct super_block *sb, u32 n, u32 type) >+{ >+ struct buffer_head *bh; >+ if ((bh = sb_bread(sb, n))) { >+ if (asfs_check_block ((void *)bh->b_data, sb->s_blocksize, n, type)) { >+ return bh; /* all okay */ >+ } >+ brelse(bh); >+ } >+ return NULL; /* error */ >+} >+ >+static inline struct buffer_head * >+asfs_getzeroblk(struct super_block *sb, int block) >+{ >+ struct buffer_head *bh; >+ bh = sb_getblk(sb, block); >+ lock_buffer(bh); >+ memset(bh->b_data, 0, sb->s_blocksize); >+ set_buffer_uptodate(bh); >+ unlock_buffer(bh); >+ return bh; >+} >+ >+static inline void >+asfs_bstore(struct super_block *sb, struct buffer_head *bh) >+{ >+ ((struct fsBlockHeader *) (bh->b_data))->checksum = >+ cpu_to_be32(asfs_calcchecksum(bh->b_data, sb->s_blocksize)); >+ mark_buffer_dirty(bh); >+} >+ >+static inline void asfs_brelse(struct buffer_head *bh) >+{ >+ brelse(bh); >+} >+ >+static inline void dec_count(struct inode *inode) >+{ >+ inode->i_nlink--; >+ mark_inode_dirty(inode); >+} >+ >+/* all prototypes */ >+ >+/* adminspace.c */ >+int allocadminspace(struct super_block *sb, u32 * block); >+int freeadminspace(struct super_block *sb, u32 block); >+int markspace(struct super_block *sb, u32 block, u32 blocks); >+int freespace(struct super_block *sb, u32 block, u32 blocks); >+int findspace(struct super_block *sb, u32 maxneeded, u32 start, u32 end, >+ u32 * returned_block, u32 * returned_blocks); >+ >+/* bitfuncs.c */ >+s16 bfffz(u32, s16); >+/* bm??? functions assumes that in-memory bitmap is in bigendian byte order */ >+s32 bmffo(u32 *, s32, s32); >+s32 bmffz(u32 *, s32, s32); >+s32 bmclr(u32 *, s32, s32, s32); >+s32 bmset(u32 *, s32, s32, s32); >+ >+/* dir.c */ >+int asfs_readdir(struct file *filp, void *dirent, filldir_t filldir); >+struct dentry *asfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd); >+ >+/* extents.c */ >+int getextent(struct super_block *sb, u32 key, struct buffer_head **ret_bh, >+ struct fsExtentBNode **ret_ebn); >+int deletebnode(struct super_block *sb, struct buffer_head *cb, u32 key); >+int deleteextents(struct super_block *sb, u32 key); >+int addblocks(struct super_block *sb, u16 blocks, u32 newspace, >+ u32 objectnode, u32 * io_lastextentbnode); >+ >+/* file.c */ >+int asfs_readpage(struct file *file, struct page *page); >+sector_t asfs_bmap(struct address_space *mapping, sector_t block); >+int asfs_writepage(struct page *page, struct writeback_control *wbc); >+int asfs_prepare_write(struct file *file, struct page *page, unsigned from, >+ unsigned to); >+void asfs_truncate(struct inode *inode); >+int asfs_file_open(struct inode *inode, struct file *filp); >+int asfs_file_release(struct inode *inode, struct file *filp); >+ >+/* inode.c */ >+struct inode *asfs_get_root_inode(struct super_block *sb); >+void asfs_read_locked_inode(struct inode *inode, void *arg); >+int asfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd); >+int asfs_mkdir(struct inode *dir, struct dentry *dentry, int mode); >+int asfs_rmdir(struct inode *dir, struct dentry *dentry); >+int asfs_delete(struct inode *dir, struct dentry *dentry); >+int asfs_rename(struct inode *old_dir, struct dentry *old_dentry, >+ struct inode *new_dir, struct dentry *new_dentry); >+int asfs_notify_change(struct dentry *dentry, struct iattr *attr); >+ >+/* namei */ >+u8 asfs_lowerchar(u8 c); >+int asfs_namecmp(u8 *s, u8 *ct, int casesensitive); >+u16 asfs_hash(u8 *name, int casesensitive); >+ >+/* nodes */ >+int getnode(struct super_block *sb, u32 nodeno, >+ struct buffer_head **ret_bh, struct fsObjectNode **ret_node); >+int createnode(struct super_block *sb, struct buffer_head **returned_cb, >+ struct fsNode **returned_node, u32 * returned_nodeno); >+int deletenode(struct super_block *sb, u32 objectnode); >+ >+/* objects */ >+struct fsObject *asfs_nextobject(struct fsObject *obj); >+struct fsObject *find_obj_by_name(struct super_block *sb, >+ struct fsObjectContainer *objcont, >+ u8 * name); >+int readobject(struct super_block *sb, u32 objectnode, >+ struct buffer_head **cb, struct fsObject **returned_object); >+int createobject(struct super_block *sb, struct buffer_head **io_cb, >+ struct fsObject **io_o, struct fsObject *src_o, >+ u8 * objname, int force); >+int deleteobject(struct super_block *sb, struct buffer_head *cb, >+ struct fsObject *o); >+int renameobject(struct super_block *sb, struct buffer_head *cb1, >+ struct fsObject *o1, struct buffer_head *cbparent, >+ struct fsObject *oparent, u8 * newname); >+ >+int addblockstofile(struct super_block *sb, struct buffer_head *objcb, >+ struct fsObject *o, u32 blocks, u32 * newspace, >+ u32 * addedblocks); >+int truncateblocksinfile(struct super_block *sb, struct buffer_head *bh, >+ struct fsObject *o, u32 newsize); >+ >+/* super.c */ >+struct super_block *asfs_read_super(struct super_block *sb, void *data, >+ int silent); >+void asfs_put_super(struct super_block *sb); >+int asfs_statfs(struct super_block *sb, struct kstatfs *buf); >+int asfs_remount(struct super_block *sb, int *flags, char *data); >+struct inode *asfs_alloc_inode(struct super_block *sb); >+void asfs_destroy_inode(struct inode *inode); >+ >+/* symlink.c */ >+int asfs_symlink_readpage(struct file *file, struct page *page); >+int asfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); >+ >+#endif /* __KERNEL__ */ >+#endif >diff -urN kernel-source-2.6.5/include/linux/asfs_fs_i.h kernel-source-2.6.5-powerpc/include/linux/asfs_fs_i.h >--- kernel-source-2.6.5/include/linux/asfs_fs_i.h 1970-01-01 01:00:00.000000000 +0100 >+++ kernel-source-2.6.5-powerpc/include/linux/asfs_fs_i.h 2004-04-12 23:39:01.000000000 +0200 >@@ -0,0 +1,32 @@ >+#ifndef __ASFS_FS_I >+#define __ASFS_FS_I >+ >+/* Extent structure located in RAM (e.g. inside inode structure), >+ currently used to store last used extent */ >+ >+struct inramExtent { >+ u32 startblock; /* Block from begginig of the file */ >+ u32 key; >+ u32 next; >+ u16 blocks; >+}; >+ >+/* inode in-kernel data */ >+ >+struct asfs_inode_info { >+ u32 firstblock; >+ u32 hashtable; >+ int modified; >+ u32 i_opencnt; >+ loff_t mmu_private; >+ struct inramExtent ext_cache; >+ struct inode vfs_inode; >+}; >+ >+/* short cut to get to the asfs specific inode data */ >+static inline struct asfs_inode_info *ASFS_I(struct inode *inode) >+{ >+ return list_entry(inode, struct asfs_inode_info, vfs_inode); >+} >+ >+#endif >diff -urN kernel-source-2.6.5/include/linux/asfs_fs_sb.h kernel-source-2.6.5-powerpc/include/linux/asfs_fs_sb.h >--- kernel-source-2.6.5/include/linux/asfs_fs_sb.h 1970-01-01 01:00:00.000000000 +0100 >+++ kernel-source-2.6.5-powerpc/include/linux/asfs_fs_sb.h 2004-04-12 23:39:01.000000000 +0200 >@@ -0,0 +1,33 @@ >+#ifndef __ASFS_FS_SB >+#define __ASFS_FS_SB >+ >+/* Amiga SFS superblock in-core data */ >+ >+struct asfs_sb_info { >+ u32 totalblocks; >+ u32 rootobjectcontainer; >+ u32 extentbnoderoot; >+ u32 objectnoderoot; >+ >+ u32 adminspacecontainer; >+ u32 bitmapbase; >+ u32 freeblocks; >+ u32 blocks_inbitmap; >+ u32 blocks_bitmap; >+ u32 block_rovingblockptr; >+ >+ uid_t uid; >+ gid_t gid; >+ umode_t mode; >+ u16 flags; >+ char *prefix; >+ char *root_volume; /* Volume prefix for absolute symlinks. */ >+}; >+ >+/* short cut to get to the asfs specific sb data */ >+static inline struct asfs_sb_info *ASFS_SB(struct super_block *sb) >+{ >+ return sb->s_fs_info; >+} >+ >+#endif
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 54684
:
33769
|
33770
|
33771
|
33772