Add dos33fs code

This was a dos33fs filesystem driver for Linux 2.4

It is included for historical reasons.
This commit is contained in:
Vince Weaver 2016-03-11 14:57:07 -05:00
parent 0dfcfcd5bd
commit 4f96a4e326
15 changed files with 2741 additions and 0 deletions

3
dos33fs-linux2.4/BUGS Normal file
View File

@ -0,0 +1,3 @@
* unsure if reading files > 30k works properly.
[no errors, but have no files that big to easily check that
all the data is being transferred properly]

11
dos33fs-linux2.4/CHANGES Normal file
View File

@ -0,0 +1,11 @@
11 October 2001
+ After about 3 weeks of work, read-only support 99% working!
+ version 0.0.3
12 October 2001
+ Fix apple-detokenizer
+ Fix file permissions
+ In theory fix files with > 30k (multiple TSL lists)
4 February 2002
+ Fix an endian bug so it works on my iBook

356
dos33fs-linux2.4/COPYING Normal file
View File

@ -0,0 +1,356 @@
NOTE! This copyright does *not* cover user programs that use kernel
services by normal system calls - this is merely considered normal use
of the kernel, and does *not* fall under the heading of "derived work".
Also note that the GPL below is copyrighted by the Free Software
Foundation, but the instance of code that it refers to (the Linux
kernel) is copyrighted by me and others who actually wrote it.
Also note that the only valid version of the GPL as far as the kernel
is concerned is _this_ license (ie v2), unless explicitly otherwise
stated.
Linus Torvalds
----------------------------------------
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

19
dos33fs-linux2.4/CREDITS Normal file
View File

@ -0,0 +1,19 @@
This file follows the same format as Linus Torvalds' CREDITS file. See
/usr/src/linux/CREDITS for more information.
----------
N: Matt Jensen
E: mjensen@obvion.com
D: Creator and chief programmer
S: Wisconsin, United States of America
N: Linus Torvalds et al
E: Various
D: Model works and documentation: Minix FS, VFS interface, etc.
S: Various
N: David Wilson
E:
D: Interface and code suggestions
S: Australia

21
dos33fs-linux2.4/Makefile Normal file
View File

@ -0,0 +1,21 @@
CC=gcc
CFLAGS= -O2 -Wall -DDEBUG_LEVEL=0 -DCONFIG_DOS33_FS -D__KERNEL__ -DMODULE -I/usr/src/linux/include
OBJS=file.o dir.o dentry.o inode.o misc.o super.o
dos33.o: $(OBJS)
$(LD) -r $^ -o $@
file.o: dos33.h dos33_fs.h file.c
dir.o: dos33.h dos33_fs.h dir.c
dentry.o: dos33.h dos33_fs.h dentry.c
inode.o: dos33.h dos33_fs.h inode.c
super.o: dos33.h dos33_fs.h super.c
misc.o: dos33.h dos33_fs.h misc.c
clean:
rm -rf *.o *~

134
dos33fs-linux2.4/README Normal file
View File

@ -0,0 +1,134 @@
NOTE!!!! This driver only works with the ancient Linux-2.4 kernel
It will not run on anything recent.
Plans are to make a FUSE-capable driver, see the ../dos33fs-fuse directory
Apple II DOS 3.3 Filesystem for Linux
by Vince Weaver (vince@deater.net)
http://www.deater.net/weave/vmwprod/apple
based on ProDos filesystem code
Copyright (c) 2001 Matt Jensen (mjensen@obvion.com)
http://www.obvion.com/matt/prodos/
[-------------------------------------------------------------------]
Background:
In January of 1978, Apple Computer demoed the DISK ][ drive,
arguably the first inexpensive 5 1/4" floppy drive for a personal
computer. It was a very clever hack by Steve Wozniak, and was
welcomed by Apple ][ users who until now had to make do with
a casette tape interface.
Dos 3.1 was released in 1978. Dos 3.2 and 3.2.1 were released
in 1979. While both worked, neither were integrated very well
with the Apple ][ computers of the time and had their share of bugs.
In August of 1980 Dos 3.3 was released. It required not only
an OS upgrade, but also a hardware one as well. Older DOS's
could read 113.75k (35 tracks*13 sectors*256bytes). Under
Dos 3.3 the disks could hold 140k (35tracks*16sectors*256bytes).
Dos 3.3 was the standard disk OS on Apple ]['s for a long time,
but it was limited to only 5 1/4" disks. Eventually it was
replaced by ProDos, which was a weird combination of Dos 3.3 and HFS+.
[------------------------------------------------------------------]
Technical Info:
* Partition size: 140k (in theory the filesystem can support more,
but I doubt it ever did it most cases).
* sector [block] size: 256bytes. Which makes it fun trying to make
Linux deal with it properly.
* Filenames: up to 30 characters in length, 7-bit ASCII.
First character had to be > 63. No commas or colons.
Padded on the right with spaces.
Besides that, anything goes [including control characters,
NULL's, and \, which make it interesting as a Unix filesystem]
* 7bits of metadata: Indicate file type [binary, BASIC, text, etc]
* "Lock": possible to "LOCK" files, that is make read-only
* holes: filesystem supports holes in files [though Linux support of
this a bit troublesome because of 256 byte block issues].
* Timestamp: no timestamp possible. The driver assigns an arbitrary
date of 13 February 1978 to all files. [2 1/2 years
too early for DOS 3.3, but it is my birthday....]
[---------------------------------------------------------------]
Usage:
You need to be running a 2.4.x linux kernel. Older versions
not supported currently.
The easiest way to do this is get a "disk image" of the type
used for Apple II emulators.
Various web pages can help you make these from your old Apple Disks,
assuming you have a working Apple II, a modern PC, and a serial
connection between the two.
First, be sure your Linux kernel has "loopback filesystem support"
Then, set up the disk image you want as a loopback device as root:
/sbin/losetup /dev/loop0 ./green.dsk
Where "green.dsk" can be any image you might have.
Next, compile the included driver [ "make"]. As root, install
the dos33.o module
/sbin/insmod ./dos33.o
Next, mount the filesystem
mount -t dos33 /dev/loop0 /mnt
And if all went well, you can now do an "ls /mnt" or wherever,
and get the file listing.
You can use the "asoft_detoken" program in the ./util
directory to dump Applesoft basic programs into plain text
asoft_detoken < /mnt/HELLO
[----------------------------------------------------------]
Future plans:
Make the driver read/write. Right now it is read-only.
Maybe add some more utilities.
Handle the file-type metadata somehow.
Far-out-there.... write a linux block-device for the DISK ][
drive, so you can actually hook the old drives and disks up
directly to your linux box....
[-------------------------------------------------------------------]
References:
http://apple2history.org/ -- great history site
http://ground.icaen.uiowa.edu/apple2/ -- treasure trove of apple][ info
[-------------------------------------------------------------------]
Added note:
if anyone has a copy of "Inside Apple DOS" they'd be willing
to part with, please let me know....

2
dos33fs-linux2.4/TODO Normal file
View File

@ -0,0 +1,2 @@
* R/W support
* support for metadata

92
dos33fs-linux2.4/dentry.c Normal file
View File

@ -0,0 +1,92 @@
/*****************************************************************************
* dentry.c
* dentry operations.
*
* Apple II DOS 3.3 Filesystem Driver for Linux 2.4.x
* Copyright (c) 2001 Vince Weaver
* Copyright (c) 2001 Matt Jensen.
* This program is free software distributed under the terms of the GPL.
*****************************************************************************/
/*= Kernel Includes ========================================================*/
#include <linux/time.h>
#include <linux/fs.h>
/*= DOS 3.3 Includes =======================================================*/
#include "dos33.h"
/*= Forward Declarations ====================================================*/
/* For dos33_dentry_operations. */
int dos33_hash_dentry(struct dentry *,struct qstr *);
int dos33_compare_dentry(struct dentry *,struct qstr *,struct qstr *);
/*= Preprocessor Macros =====================================================*/
/*= VFS Interface Structures ================================================*/
struct dentry_operations dos33_dentry_operations = {
d_hash: dos33_hash_dentry,
d_compare: dos33_compare_dentry
};
/*= Private Functions =======================================================*/
/*= Interface Functions =====================================================*/
/*****************************************************************************
* dos33_hash_dentry()
* Check a name for validity under DOS33 naming rules; if it is valid, hash
* it.
*****************************************************************************/
int dos33_hash_dentry(struct dentry *de,struct qstr *qstr) {
unsigned long hash = 0;
int len = 0;
int i = 0;
/* Ensure that we have a valid ProDOS name. */
i = dos33_check_name(qstr);
if (i) return i;
/* Hash the name. */
if (len>DOS33_MAX_NAME_LEN) len=DOS33_MAX_NAME_LEN;
hash = init_name_hash();
for(i = 0;i < len;i++) hash = partial_name_hash(qstr->name[i],hash);
qstr->hash = end_name_hash(hash);
return 0;
}
/*****************************************************************************
* dos33_compare_dentry()
* Compare two hashed DOS 3.3 names.
*****************************************************************************/
int dos33_compare_dentry(struct dentry *de,struct qstr *q1,struct qstr *q2) {
int len = 0;
int i = 0;
/* q2 has not been validated yet. */
i = dos33_check_name(q2);
if (i) return i;
/* Ignore characters past the maximum DOS 3.3 name length. */
len = q1->len;
if (q1->len >= DOS33_MAX_NAME_LEN) {
if (q2->len < DOS33_MAX_NAME_LEN) return 1;
len = DOS33_MAX_NAME_LEN;
}
else if (len != q2->len) return ~0;
/* Compare the strings. */
for (i = 0;i < len;i++) {
if (q1->name[i] != q2->name[i]) return ~0;
}
return 0;
}

593
dos33fs-linux2.4/dir.c Normal file
View File

@ -0,0 +1,593 @@
/*****************************************************************************
* dir.c
* File and inode operations for directories.
*
* Apple II DOS 3.3 Filesystem Driver for Linux 2.4.x
* Copyright (c) 2001 Vince Weaver
* Copyright (c) 2001 Matt Jensen.
* This program is free software distributed under the terms of the GPL.
*****************************************************************************/
/*= Kernel Includes =========================================================*/
#include <linux/blkdev.h>
/*= DOS 3.3 Includes =======================================================*/
#include "dos33.h"
/*= Forward Declarations ===================================================*/
/* For dos33_dir_inode_operations. */
struct dentry *dos33_lookup(struct inode *,struct dentry *);
int dos33_create(struct inode *,struct dentry *,int);
int dos33_unlink(struct inode *,struct dentry *);
int dos33_rename(struct inode *,struct dentry *,struct inode *,struct dentry *);
/* For dos33_dir_operations. */
int dos33_readdir(struct file *,void *,filldir_t);
/*= VFS Interface Structures ================================================*/
struct inode_operations dos33_dir_inode_operations = {
lookup: dos33_lookup,
create: dos33_create,
unlink: dos33_unlink,
rename: dos33_rename
};
struct file_operations dos33_dir_operations = {
read: generic_read_dir,
readdir: dos33_readdir
/* fsync: file_fsync */
};
/*****************************************************************************
* dos33_new_dir_block()
* Allocate and initialize a new directory block.
*****************************************************************************/
int dos33_expand_dir(struct super_block *sb,u16 block) {
int result = 0;
// u16 new_block = 0;
// struct buffer_head *dir_bh = NULL;
// struct dos33_dir_block *dir = NULL;
DOS33_DEBUG("expand_dir\n");
#if 0
/* Try to allocate a new block. */
new_block = prodos_alloc_block(sb);
if (!new_block) {
result = -ENOSPC;
goto out_cleanup;
}
/* Read the block. */
dir_bh = prodos_bread(sb,new_block);
if (!dir_bh) {
result = -EIO;
goto out_cleanup;
}
dir = (void*)dir_bh->b_data;
/* Initialize the block. */
memset(dir,0,PRODOS_BLOCK_SIZE);
dir->header.prev = cpu_to_le16(block);
dir->header.next = 0;
mark_buffer_dirty(dir_bh);
result = new_block;
out_cleanup:
if (dir_bh) prodos_brelse(dir_bh);
#endif
return result;
}
/*****************************************************************************
* dos33_find_entry()
* Search directory @inode for an entry. If @name is non-NULL, the directory
* is searched for an entry with matching name; if @name is NULL, the
* directory is searched (and possibly expanded) for an unused entry. Zero is
* returned on failure; the found entry's inode number is returned on success.
*****************************************************************************/
unsigned long dos33_find_entry(struct inode *inode,struct qstr *name) {
unsigned long result = 0;
u32 catalog_block = (DOS33_INO_TRACK(inode->i_ino)<<4)+
DOS33_INO_SECTOR(inode->i_ino);
u32 odd=0,entry_num=0;
struct buffer_head *bh = NULL;
struct dos33_catalog_sector *catalog = NULL;
DOS33_DEBUG("find entry: %i %x\n",(int)inode->i_ino,(int)catalog_block);
/* Scan the directory for a matching entry. */
while (catalog_block) {
/* Load next directory block when necessary. */
if (!bh) {
odd=catalog_block%2;
/* Load the block. */
DOS33_DEBUG("==Loading block %x\n",catalog_block);
bh = dos33_bread(inode->i_sb,catalog_block);
if (!bh) {
DOS33_DEBUG("dos33_bread() failed for block %d\n",catalog_block);
goto out_cleanup;
}
/* deal with 256byte sector size */
if (odd) {
catalog = (struct dos33_catalog_sector*)(bh->b_data+256);
}
else {
catalog = (struct dos33_catalog_sector*)(bh->b_data);
}
}
/* Searching for an empty entry. FIX ME */
if (!name) {
DOS33_DEBUG("== no name dir.c FIXME\n");
// result = DOS33_MAKE_INO(0,(cur_block>>4)&0xffff,cur_block&0xf);
goto out_cleanup;
}
else {
int qlen=name->len;
int mismatch=0;
int i;
struct dos33_file_t *file_ent=&catalog->files[entry_num];
/* Do the names match? */
for(i=0;i<qlen;i++) {
if ( name->name[i] != ((file_ent->file_name[i])&0x7f)) mismatch++;
}
/* If they match, return the inode */
if (!mismatch) {
DOS33_DEBUG("==MATCH %s\n",name->name);
result = DOS33_MAKE_INO(0,entry_num,
(catalog_block>>4)&0x7f,
(catalog_block)&0xf);
goto out_cleanup;
}
}
/* Advance to next entry. */
/* For now only handle first 7 files */
if (++entry_num >= 7) {
DOS33_DEBUG("ENDDDDDDDDDDDING\n");
entry_num=0;
catalog_block = ((catalog->next.track)<<4)+catalog->next.sector;
DOS33_DEBUG("== next block %x\n",catalog_block);
/* Release previous block. */
dos33_brelse(bh);
bh = NULL;
}
}
out_cleanup:
if (bh) {
dos33_brelse(bh);
bh = NULL;
}
return result;
}
/*****************************************************************************
* prodos_unlink_all()
* Unlink (delete) all forks of the ProDOS file represented by an @inode.
*****************************************************************************/
#if 0
int dos33_unlink_all(struct inode *inode,struct dos33_dir_entry *ent) {
int result = 0;
const u16 dblk = PRODOS_INO_DBLK(inode->i_ino);
const u8 dent = PRODOS_INO_DENT(inode->i_ino);
u8 dfrk = PRODOS_INO_DFORK(inode->i_ino);
struct buffer_head *ext_bh = NULL;
/* We may have to delete TWO forks. */
if (PRODOS_ISEXTENDED(*ent)) {
struct prodos_ext_key_block *ext_block = NULL;
/* Load the extended directory block. */
ext_bh = prodos_bread(inode->i_sb,PRODOS_I(inode)->i_key);
if (!ext_bh) {
result = -EIO;
goto out_cleanup;
}
ext_block = (void*)ext_bh->b_data;
/* Free the resource fork. */
prodos_free_tree_blocks(inode->i_sb,ext_block->res.stype << 4,
le16_to_cpu(ext_block->res.key_block),
le16_to_cpu(ext_block->res.blocks_used));
/* Free the data fork. */
prodos_free_tree_blocks(inode->i_sb,ext_block->data.stype << 4,
le16_to_cpu(ext_block->data.key_block),
le16_to_cpu(ext_block->data.blocks_used));
/* Release the extended directory block. */
prodos_brelse(ext_bh);
ext_bh = NULL;
/* Free the extended directory block. */
prodos_free_block(inode->i_sb,PRODOS_I(inode)->i_key);
}
/* ...or we may only have to delete one fork. */
else {
prodos_free_tree_blocks(inode->i_sb,PRODOS_I(inode)->i_stype,
le16_to_cpu(ent->key_block),
le16_to_cpu(ent->blocks_used));
}
/* Update this inode. */
inode->i_nlink--;
mark_inode_dirty(inode);
/* Unlink the resource fork inode. */
if (PRODOS_I(inode)->i_stype == PRODOS_STYPE_EXTENDED) {
inode = iget(inode->i_sb,PRODOS_MAKE_INO(dblk,dent,PRODOS_DFORK_RES));
if (inode) {
down(&inode->i_sem);
inode->i_nlink--;
mark_inode_dirty(inode);
up(&inode->i_sem);
iput(inode);
}
}
/* We may have been called on either a data fork inode OR a meta file
inode. Unlink the one upon which we were NOT called (the one we were
called on has, obviously, already been unlinked.) */
dfrk = dfrk == PRODOS_DFORK_META ? PRODOS_DFORK_DATA : PRODOS_DFORK_META;
inode = iget(inode->i_sb,PRODOS_MAKE_INO(dblk,dent,dfrk));
if (inode) {
down(&inode->i_sem);
inode->i_nlink--;
mark_inode_dirty(inode);
up(&inode->i_sem);
iput(inode);
}
/* Mark the directory entry as deleted. */
ent->name[0] &= 0x0f;
result = 1;
out_cleanup:
if (ext_bh) prodos_brelse(ext_bh);
return result;
}
#endif
/*****************************************************************************
* prodos_unlink_res()
* Unlink (delete) the resource fork of the ProDOS file represented by an
* @inode. This is the most involved of the unlink operations. The resource
* fork is deleted and its blocks freed, then the file is collapsed into a
* a regular (non-extended) file by copying the data fork metainformation from
* the extended directory block into the base directory entry itself.
*****************************************************************************/
#if 0
int dos33_unlink_res(struct inode *inode,struct prodos_dir_entry *ent) {
int result = 0;
struct buffer_head *key_bh = NULL;
struct prodos_ext_key_block *key_block = NULL;
/* Need the key block so we can copy data fork info into the dir entry. */
key_bh = prodos_bread(inode->i_sb,PRODOS_I(inode)->i_key);
if (!key_bh) {
result = -EIO;
goto out_cleanup;
}
key_block = (void*)key_bh->b_data;
/* Update the directory entry. Note that we don't have to worry about byte
order since we're copying from one on-disk entry to another. */
ent->name[0] &= 0x0f;
ent->name[0] |= key_block->data.stype << 4;
ent->key_block = key_block->data.key_block;
ent->blocks_used = key_block->data.blocks_used;
memcpy(&ent->eof,&key_block->data.eof,3);
/* TODO: Update the data and meta inodes here (stype, key block, size, blocks used) */
/* Free affected disk blocks. */
prodos_free_tree_blocks(inode->i_sb,key_block->res.stype << 4,
le16_to_cpu(key_block->res.key_block),
le16_to_cpu(key_block->res.blocks_used));
prodos_free_block(inode->i_sb,PRODOS_I(inode)->i_key);
/* The inode is now dirty; also return 1 to cause the directory buffer
to be marked dirty. */
mark_inode_dirty(inode);
result = 1;
out_cleanup:
if (key_bh) prodos_brelse(key_bh);
return result;
}
#endif
/*= Interface Functions =====================================================*/
/*****************************************************************************
* dos33_lookup()
* Search a directory inode for an entry.
*****************************************************************************/
struct dentry *dos33_lookup(struct inode *inode,struct dentry *dentry) {
SHORTCUT struct dos33_sb_info * const psb = DOS33_SB(inode->i_sb);
struct dentry *result = NULL;
unsigned long ino = 0;
DOS33_DEBUG("Lookup\n");
/* Grab directory lock. */
down(&psb->s_dir_lock);
/* Attempt to find matching entry and get its inode number. */
ino = dos33_find_entry(inode,&dentry->d_name);
if (!ino) {
result = ERR_PTR(-ENOENT);
goto out_cleanup;
}
/* Get the inode and set up a dentry. */
inode = iget(inode->i_sb,ino);
if (!inode) {
DOS33_DEBUG("iget() failed for ino 0x%08x",(int)ino);
result = ERR_PTR(-EACCES);
goto out_cleanup;
}
dentry->d_op = &dos33_dentry_operations;
d_add(dentry,inode);
out_cleanup:
up(&psb->s_dir_lock);
return result;
}
/*****************************************************************************
* prodos_create()
* Create a new entry in directory inode @dir. Note that the VFS has already
* checked that the filename is unique within the directory.
*****************************************************************************/
int dos33_create(struct inode *dir,struct dentry *dentry,int mode) {
// SHORTCUT struct prodos_sb_info * psb = PRODOS_SB(dir->i_sb);
int result = 0;
// unsigned long ino = 0;
// struct buffer_head *dir_bh = NULL;
DOS33_DEBUG("create\n");
#if 0
PRODOS_ERROR_0(dir->i_sb,"called");
/* Grab directory lock. */
down(&psb->s_dir_lock);
/* Get an unused "inode" in the directory. */
ino = prodos_find_entry(dir,NULL);
if (!ino) {
result = -ENOSPC;
goto out_cleanup;
}
/* Read the directory block. */
/* dir_bh = prodos_bread(dir->i_sb,PRODOS_INO_DBLK(ino));
if (!dir_bh) {
result = -EIO;
goto out_cleanup;
}*/
result = -EPERM;
out_cleanup:
if (dir_bh) prodos_brelse(dir_bh);
up(&psb->s_dir_lock);
#endif
return result;
}
/*****************************************************************************
* prodos_unlink()
*****************************************************************************/
/* NOTE: The VFS holds the inode->i_zombie semaphore during this call. */
/* The big kernel lock is also held for exactly the duration of this call. */
int dos33_unlink(struct inode *inode,struct dentry *dentry) {
// SHORTCUT struct prodos_sb_info * const psb = PRODOS_SB(inode->i_sb);
// SHORTCUT struct inode * const victim = dentry->d_inode;
int result = 0;
// struct buffer_head *dir_bh = NULL;
// struct prodos_dir_entry *ent = NULL;
DOS33_DEBUG("unlink\n");
#if 0
/* Grab directory lock. */
down(&psb->s_dir_lock);
/* Load the directory block. */
dir_bh = prodos_bread(inode->i_sb,PRODOS_INO_DBLK(victim->i_ino));
if (!dir_bh) {
result = -EIO;
goto out_cleanup;
}
ent = &((struct prodos_dir_block*)dir_bh->b_data)->entries[PRODOS_INO_DENT(victim->i_ino)];
/* Dispatch appropriate unlink function. */
switch (PRODOS_INO_DFORK(victim->i_ino)) {
case PRODOS_DFORK_DATA:
result = prodos_unlink_all(victim,ent);
break;
case PRODOS_DFORK_META:
result = prodos_unlink_all(victim,ent);
break;
case PRODOS_DFORK_RES:
if (!PRODOS_ISEXTENDED(*ent)) {
result = -ENOENT;
goto out_cleanup;
}
result = prodos_unlink_res(victim,ent);
break;
}
/* The prodos_unlink_*() helper returned 1 if it dirtied the dir block. */
if (result == 1) {
mark_buffer_dirty(dir_bh);
result = 0;
}
out_cleanup:
if (dir_bh) prodos_brelse(dir_bh);
up(&psb->s_dir_lock);
#endif
return result;
}
/*****************************************************************************
* prodos_rename()
*****************************************************************************/
int dos33_rename(struct inode *oi,struct dentry *od,struct inode *ni,struct dentry *nd) {
int result = 0;
DOS33_DEBUG("rename\n");
#if 0
/* Our inode number usage prevents all but in-directory renames. */
if (oi != ni) {
result = -EPERM;
goto out_cleanup;
}
result = -EPERM;
out_cleanup:
#endif
return result;
}
/*****************************************************************************
* dos33_readdir()
* Standard file operation; reads a directory and returns its entries via
* the filldir() function supplied by the caller.
*****************************************************************************/
int dos33_readdir(struct file *filp,void *dirent,filldir_t filldir) {
SHORTCUT struct super_block * const sb = filp->f_dentry->d_sb;
SHORTCUT struct inode * const inode = filp->f_dentry->d_inode;
SHORTCUT struct inode * const parent = filp->f_dentry->d_parent->d_inode;
int result = 0;
struct buffer_head *bh = NULL;
struct dos33_catalog_sector *catalog = NULL;
u32 dent=0;
u32 catalog_track = DOS33_INO_TRACK(filp->f_pos);
u32 catalog_sector = DOS33_INO_SECTOR(filp->f_pos);
u32 catalog_block;
u32 odd;
struct dos33_file_t *ent = NULL;
char name[DOS33_MAX_NAME_LEN + 3] = "";
int nlen;
unsigned int ino = 0;
DOS33_DEBUG("readdir\n");
/* Handle the special '.' and '..' entries. */
switch ( (long int)filp->f_pos) {
case 0: /* Add the '.' entry. */
if (filldir(dirent,".",1,0,inode->i_ino,DT_DIR) < 0)
goto out_cleanup;
/* fpos is simply incremented at this point. */
filp->f_pos++;
/* Fall through. */
case 1: /* Add the '..' entry. */
if (filldir(dirent,"..",2,1,parent->i_ino,DT_DIR) < 0)
goto out_cleanup;
/* fpos takes on special format after second entry. */
filp->f_pos = DOS33_MAKE_INO(0,0,
DOS33_INO_TRACK(inode->i_ino),
DOS33_INO_SECTOR(inode->i_ino));
}
/* Grab directory lock. */
down(&DOS33_SB(sb)->s_dir_lock);
/* After the two special entries, filp->f_pos is the "inode number" of the
next file (or fork) in the directory. See the PRODOS_INO_*() and
PRODOS_MAKE_INO() macros for the format of this value. When all entries
have been returned filp->f_pos is set to 3 to signal end-of-directory. */
while (filp->f_pos != 3) {
catalog_block=((catalog_track<<4)+catalog_sector);
odd=catalog_block%2;
DOS33_DEBUG("filp: %x dblk: %x %i %i\n",(int)filp->f_pos,(int)catalog_block,(int)catalog_track,(int)catalog_sector);
/* Load the block if necessary. */
if (!bh) {
bh = dos33_bread(sb,catalog_block);
if (!bh) {
result = -EIO;
goto out_cleanup;
}
/* handle 256 byte sectors */
if (odd) {
catalog = (struct dos33_catalog_sector*)(bh->b_data+256);
}
else {
catalog = (struct dos33_catalog_sector*)bh->b_data;
}
}
ent = &catalog->files[dent];
/* Copy and modify the name as necessary. */
if (ent->file_name[0]!=0) {
memcpy(name,&(ent->file_name),DOS33_MAX_NAME_LEN+1);
nlen=dos33_convert_filename(name);
/* Build inode number. */
ino = DOS33_MAKE_INO(0,dent,catalog_track,
catalog_sector);
/* Finally, attempt to return the entry via filldir(). */
if (filldir(dirent,&name[0],nlen,filp->f_pos,ino,DT_UNKNOWN) < 0)
goto out_cleanup;
}
dent++;
if (dent>6) {
dent=0;
dos33_brelse(bh);
bh=NULL;
catalog_track=(catalog->next.track);
catalog_sector=(catalog->next.sector);
if ((!catalog_track) && (!catalog_sector)) {
filp->f_pos=3;
}
}
}
/* Release remaining resources and return. */
out_cleanup:
if (bh) {
dos33_brelse(bh);
bh = NULL;
}
up(&DOS33_SB(sb)->s_dir_lock);
return result;
}

148
dos33fs-linux2.4/dos33.h Normal file
View File

@ -0,0 +1,148 @@
/*****************************************************************************
* dos33.h
* Includes, definitions, and helpers pertaining to the Linux driver
* implementation.
*
* Apple II Apple DOS 3.3 Filesystem Driver for Linux 2.4.x
* Copyright (c) 2001 Vince Weaver
* based on code Copyright (c) 2001 Matt Jensen.
* This program is free software distributed under the terms of the GPL.
*****************************************************************************/
#ifndef __DOS33_DOS33_H
#define __DOS33_DOS33_H
/*= ProDOS Includes =========================================================*/
#include "dos33_fs.h"
/*= Code Readability Tags ===================================================*/
/* SHORTCUT identifies shortcuts to buried struct members, etc. */
#define SHORTCUT /* */
/* Simplify access to custom superblock info. */
#define DOS33_SB(s) ((struct dos33_sb_info *)((s)->u.generic_sbp))
#define DOS33_I(i) ((struct dos33_inode_info *)&(i)->u.minix_i)
#define DOS33_INO_DENT(ino) ((ino)>>31)
#define DOS33_INO_ENTRY(ino) (((ino)>>16)&0xff)
#define DOS33_INO_TRACK(ino) (((ino)>>8)&0xff)
#define DOS33_INO_SECTOR(ino) ((ino)&0xff)
#define DOS33_MAKE_INO(__d,__n,__t,__s) ( ((__d)<<31) | (((__n)&0xff)<<16) | (((__t)&0xff)<<8) | (__s &0xff))
/*= Structure Definitions ===================================================*/
/* super_block information specific to ProDOS filesystems. */
struct dos33_sb_info {
u32 s_flags;
/* Items relating to partition location. */
u32 s_part_start;
u32 s_part_size;
u8 s_part[32];
/* Items relating to the volume bitmap. */
struct semaphore s_bm_lock;
u32 bitmaps[0x64]; /* one extra to act as NULL terminator */
u16 s_bm_start;
int s_bm_free;
/* Items relating to miscellaneous locking and serialization. */
struct semaphore s_dir_lock;
};
/* inode information specific to ProDOS "inodes." Note that this structure is
never actually instantiated. It is simply overlaid upon inode.u.minix_i to
avoid the need to modify fs.h in the standard Linux source. Obviously, this
limits the prodos_inode_info structure to a size <= the size of
struct minix_inode_info. */
struct dos33_inode_info {
u8 i_flags;
u8 i_filetype;
u8 i_stype;
u16 i_key;
u16 i_auxtype;
u8 i_access;
};
struct dos33_track_sector {
u8 track;
u8 sector;
} __attribute__((packed));
struct dos33_vtol {
u8 four;
struct dos33_track_sector catalog;
u8 dos_version;
u8 unused1[2];
u8 volume;
u8 unused2[0x20];
u8 ts_pairs;
u8 unused3[8];
u8 last_track;
u8 allocation_direction;
u8 unused4[2];
u8 tracks_per_disk;
u8 sectors_per_track;
u16 bytes_per_sector;
u32 bitmaps[0x23];
u8 unused5[0x3b];
} __attribute__((packed));
struct dos33_file_t {
struct dos33_track_sector first_tsl;
u8 file_type;
u8 file_name[0x1e]; /* high bit set, padded with spaces */
u16 num_sectors;
} __attribute__((packed));
struct dos33_catalog_sector {
u8 unused1;
struct dos33_track_sector next;
u8 unused[8];
struct dos33_file_t files[7];
} __attribute__((packed));
struct dos33_ts_list {
u8 unused1;
struct dos33_track_sector next;
u8 unused2[2];
u16 current_sectors_deep;
u8 unused3[5];
struct dos33_track_sector data_location[122];
} __attribute__((packed));
/*= Externals ===============================================================*/
/* dir.c */
extern struct inode_operations dos33_dir_inode_operations;
extern struct file_operations dos33_dir_operations;
/* file.c */
extern struct inode_operations dos33_file_inode_operations;
extern struct file_operations dos33_file_operations;
extern struct address_space_operations dos33_address_space_operations;
/* dentry.c */
extern struct dentry_operations dos33_dentry_operations;
/* inode.c */
extern void dos33_read_inode(struct inode *);
extern void dos33_write_inode(struct inode *,int);
extern void dos33_put_inode(struct inode *);
/* super.c */
extern int dos33_count_free_blocks(struct super_block *sb);
extern int dos33_alloc_block(struct super_block *sb);
extern int dos33_free_block(struct super_block *sb,u16 block);
extern int dos33_free_tree_blocks(struct super_block *sb,u8,u16,u16);
/* misc.c */
extern int dos33_convert_filename(char *filename);
extern int dos33_check_name(struct qstr *);
extern struct buffer_head *dos33_bread(struct super_block *,int);
extern void dos33_brelse(struct buffer_head *);
#endif

View File

@ -0,0 +1,48 @@
/*****************************************************************************
* prodos/prodos_fs.h
* Includes, definitions, and helpers pertaining to the ProDOS filesystem
* implementation.
*
* Apple II ProDOS Filesystem Driver for Linux 2.4.x
* Copyright (c) 2001 Matt Jensen.
* This program is free software distributed under the terms of the GPL.
*
* 18-May-2001: Created
*****************************************************************************/
#ifndef __DOS33_DOS33_FS_H
#define __DOS33_DOS33_FS_H
/*= Preprocessor Constants ==================================================*/
/* Block size. */
#define DOS33_BLOCK_SIZE 0x200
#define DOS33_BLOCK_SIZE_BITS 9 /* log base-2 of PRODOS_BLOCK_SIZE */
/* Number of entries per directory block. */
#define DOS33_DIR_ENTS_PER_BLOCK 7
/* Various limits and maximums. */
#define DOS33_MAX_NAME_LEN 0x1e
#define DOS33_MAX_FILE_SIZE 0x00ffffff
#define DOS33_SUPER_MAGIC 0x02131978
#define DOS33_VOLUME_DIR_BLOCK (0x11*0x10)
#define DOS33_VOLUME_DIR_TRACK 0x11
#define DOS33_VOLUME_DIR_SECTOR 0x00
#define TWO_BYTES_TO_SHORT(__x,__y) ((((int)__y)<<8)+__x)
#if (DEBUG_LEVEL==1)
#define DOS33_DEBUG printk
#else
#define DOS33_DEBUG if (0) printk
#endif
#define DOS33_ERROR printk
#endif

491
dos33fs-linux2.4/file.c Normal file
View File

@ -0,0 +1,491 @@
/*****************************************************************************
* file.c
* File and inode operations for regular files.
*
* Apple II DOS 3.3 Filesystem Driver for Linux 2.4.x
* Copyright (c) 2001 Vince Weaver
* Copyright (c) 2001 Matt Jensen.
* This program is free software distributed under the terms of the GPL.
*****************************************************************************/
/*= Kernel Includes =========================================================*/
#include <linux/types.h>
#include <linux/locks.h>
/*= DOS 3.3 Includes =======================================================*/
#include "dos33.h"
/*= Forward Declarations ====================================================*/
/* For dos33_address_space_operations. */
int dos33_readpage(struct file *,struct page *);
int dos33_writepage(struct page *);
int dos33_prepare_write(struct file *,struct page *,unsigned int, unsigned int);
int dos33_commit_write(struct file*,struct page *,unsigned int,unsigned int);
int dos33_bmap(struct address_space *,long);
/*= VFS Interface Structures ================================================*/
struct inode_operations dos33_file_inode_operations = {
};
struct file_operations dos33_file_operations = {
read: generic_file_read,
write: generic_file_write,
mmap: generic_file_mmap
};
struct address_space_operations dos33_address_space_operations = {
readpage: dos33_readpage,
writepage: dos33_writepage,
sync_page: block_sync_page,
prepare_write: dos33_prepare_write,
commit_write: dos33_commit_write,
bmap: dos33_bmap
};
/*= Interface Functions =====================================================*/
/*****************************************************************************
* dos33_get_block()
* Translate a block number within an @inode into a logical disk block number.
*****************************************************************************/
int dos33_get_block(struct inode *inode,long block,struct buffer_head *bh_res,int create) {
int result = 0;
struct dos33_catalog_sector *catalog = NULL;
struct dos33_file_t *file_ent;
struct dos33_ts_list *tsl;
int i;
u32 catalog_block=(DOS33_INO_TRACK(inode->i_ino)<<4)+
DOS33_INO_SECTOR(inode->i_ino);
u32 data_block;
u32 odd,half_block;
u32 file_entry=DOS33_INO_ENTRY(inode->i_ino);
u32 tsl_block;
struct buffer_head *bh = NULL;
struct buffer_head *bh2 = NULL;
struct buffer_head *bh_temp=NULL;
DOS33_DEBUG("** get_block 0x%x from file 0x%x\n",(int)block,(int)inode->i_ino);
#if 0
/* Verify that the block number is valid. */
if ((block < 0) || (block >= inode->i_blocks)) {
printk("** bad block number: 0< 0x%x < 0x%x\n",(int)block,(int)inode->i_blocks);
result = -EIO;
goto out_cleanup;
}
#endif
if (!bh) {
odd=catalog_block%2;
/* Load the block. */
DOS33_DEBUG("** Loading block %x\n",catalog_block);
bh = dos33_bread(inode->i_sb,catalog_block);
if (!bh) {
DOS33_ERROR("** dos33_bread() failed for block %d\n",catalog_block);
goto out_cleanup;
}
/* deal with 256byte sector size */
if (odd) {
catalog = (struct dos33_catalog_sector*)(bh->b_data+256);
}
else {
catalog = (struct dos33_catalog_sector*)(bh->b_data);
}
}
file_ent=&catalog->files[file_entry];
tsl_block= (file_ent->first_tsl.track<<4)+file_ent->first_tsl.sector;
DOS33_DEBUG("** going to try reading tsl from 0x%x\n",tsl_block);
odd=tsl_block%2;
/* Load the block. */
bh2 = dos33_bread(inode->i_sb,tsl_block);
if (!bh2) {
DOS33_ERROR("** dos33_bread() failed for block %d\n",tsl_block);
goto out_cleanup;
}
/* deal with 256byte sector size */
if (odd) {
tsl = (struct dos33_ts_list*)(bh2->b_data+256);
}
else {
tsl = (struct dos33_ts_list*)(bh2->b_data);
}
/* each tsl list only holds 122 sectors */
/* so if bigger, we must follow the chain to the proper tsl */
if ((block*2) > 122) {
DOS33_DEBUG("!! need tsl %i\n",(int)((block*2)/122));
for (i=0;i< ((block*2)/122);i++) {
tsl_block=((tsl->next.track)<<4)+tsl->next.sector;
if (tsl_block==0) {
DOS33_ERROR("dos33.o: NULL TSL BLOCK!\n");
goto out_cleanup;
}
DOS33_DEBUG("!! going to tsl in block 0x%x\n",tsl_block);
dos33_brelse(bh2);
bh2=NULL;
odd=tsl_block%2;
/* Load the block. */
bh2 = dos33_bread(inode->i_sb,tsl_block);
if (!bh2) {
DOS33_ERROR("dos33_bread() failed for block %d\n",tsl_block);
goto out_cleanup;
}
/* deal with 256byte sector size */
if (odd) {
tsl = (struct dos33_ts_list*)(bh2->b_data+256);
}
else {
tsl = (struct dos33_ts_list*)(bh2->b_data);
}
}
/* move block to the proper value */
block=block%61;
}
/* OK, we know where the data is, not let's trick the VFS */
/* into thinking we can read 256 byte blocks */
for (half_block=0;half_block<2;half_block++) {
data_block=(u32)( ((tsl->data_location[(block*2)+half_block].track)<<4)+
tsl->data_location[(block*2)+half_block].sector);
DOS33_DEBUG("!!** found block: %x [%x %x] (pass %i request block %i)\n",
data_block,tsl->data_location[(block*2)+half_block].track,
tsl->data_location[(block*2)+half_block].sector,half_block,(int)block);
if (data_block==0) {
/* a hole.. but since we have to fake block size */
/* we fill it with zeros ourselves */
DOS33_DEBUG("** HOLE\n");
lock_buffer(bh_res);
memset(bh_res->b_data+(half_block*256),0,256);
bh_res->b_state |= (1 << BH_Mapped);
mark_buffer_uptodate(bh_res,1);
unlock_buffer(bh_res);
}
else {
bh_temp = dos33_bread(inode->i_sb,data_block);
if (!bh_temp) {
DOS33_ERROR("dos33_bread() failed for block %d\n",data_block);
goto out_cleanup;
}
if (data_block%2) {
lock_buffer(bh_res);
memcpy(bh_res->b_data+(half_block*256),bh_temp->b_data+256,256);
bh_res->b_state |= (1 << BH_Mapped);
mark_buffer_uptodate(bh_res,1);
unlock_buffer(bh_res);
}
else {
lock_buffer(bh_res);
memcpy(bh_res->b_data+(half_block*256),bh_temp->b_data,256);
bh_res->b_state |= (1 << BH_Mapped);
mark_buffer_uptodate(bh_res,1);
unlock_buffer(bh_res);
}
DOS33_DEBUG("** copying 256bytes from sector 0x%x starting with %0x %0x\n",
data_block,
(char)*(bh_temp->b_data),(char)*(bh_temp->b_data+1));
}
}
out_cleanup:
if (bh) dos33_brelse(bh);
if (bh2) dos33_brelse(bh2);
if (bh_temp) dos33_brelse(bh_temp);
return result;
}
/*****************************************************************************
* prodos_get_block_write()
* get_block_t function for write operations. This function is ugly and
* probably temporary. Ultimately it should be merged with prodos_get_block()
* and thoroughly cleaned. What you see here is basically a quick and (very)
* dirty hack.
*****************************************************************************/
int dos33_get_block_write(struct inode *inode,long block,struct buffer_head *bh_res,int create) {
// SHORTCUT struct prodos_inode_info * const pi = PRODOS_I(inode);
int result = 0;
DOS33_DEBUG("get_block_write\n");
#if 0
/* Croak on non-regular files for now. */
if ((pi->i_stype < PRODOS_STYPE_SEEDLING) || (pi->i_stype > PRODOS_STYPE_TREE)) {
PRODOS_ERROR_0(inode->i_sb,"extended files not supported for writing");
result = -EPERM;
goto out_cleanup;
}
/* Can't translate block numbers that are out of range. */
if (block >= PRODOS_MAX_FILE_SIZE >> PRODOS_BLOCK_SIZE_BITS) {
result = -EFBIG;
goto out_cleanup;
}
/* Expand the file if necessary. */
if (block >= inode->i_blocks) {
u8 new_stype = pi->i_stype;
u16 new_key = pi->i_key;
u16 new_bused = inode->i_blocks;
/* May have to convert a seedling into a sapling. */
if ((block > 0) && (new_stype == PRODOS_STYPE_SEEDLING)) {
u16 key_ptr = 0;
struct buffer_head *bh = NULL;
/* Allocate the new indirect block. */
key_ptr = prodos_alloc_block(inode->i_sb);
if (!key_ptr) {
result = -ENOSPC;
goto out_cleanup;
}
/* Load and initialize the indirect block. */
bh = prodos_bread(inode->i_sb,key_ptr);
if (!bh) {
result = -EIO;
goto out_cleanup;
}
memset(bh->b_data,0,PRODOS_BLOCK_SIZE);
PRODOS_SET_INDIRECT_ENTRY(bh->b_data,0,new_key);
mark_buffer_dirty(bh);
prodos_brelse(bh);
new_stype = PRODOS_STYPE_SAPLING;
new_key = key_ptr;
new_bused++;
}
/* May have to convert a sapling into a tree. */
if ((block > 256) && (new_stype == PRODOS_STYPE_SAPLING)) {
u16 key_ptr = 0;
struct buffer_head *bh = NULL;
/* Allocate the new double indirect block. */
key_ptr = prodos_alloc_block(inode->i_sb);
if (!key_ptr) {
result = -ENOSPC;
goto out_cleanup;
}
/* Load and initialize the double indirect block. */
bh = prodos_bread(inode->i_sb,key_ptr);
if (!bh) {
result = -EIO;
goto out_cleanup;
}
memset(bh->b_data,0,PRODOS_BLOCK_SIZE);
PRODOS_SET_INDIRECT_ENTRY(bh->b_data,0,new_key);
mark_buffer_dirty(bh);
prodos_brelse(bh);
new_stype = PRODOS_STYPE_TREE;
new_key = key_ptr;
new_bused++;
}
/* Update the inode if storage type changed. */
if (new_stype != pi->i_stype) {
pi->i_stype = new_stype;
pi->i_key = new_key;
inode->i_blocks = new_bused;
mark_inode_dirty(inode);
}
/* May need to expand indexes for a tree file. */
if (new_stype == PRODOS_STYPE_TREE) {
u16 ind_existing = ((inode->i_blocks - 1) >> 8) + 1;
u16 ind_needed = block >> 8;
u16 ind_ptr = 0;
struct buffer_head *dind_bh = NULL;
struct buffer_head *ind_bh = NULL;
dind_bh = prodos_bread(inode->i_sb,pi->i_key);
if (!dind_bh) {
result = -EIO;
goto out_cleanup;
}
for (;ind_existing < ind_needed;ind_existing++) {
ind_ptr = prodos_alloc_block(inode->i_sb);
if (!ind_ptr) {
result = -ENOSPC;
goto out_cleanup;
}
ind_bh = prodos_bread(inode->i_sb,ind_ptr);
if (!ind_bh) {
result = -EIO;
goto out_cleanup;
}
memset(ind_bh,0,PRODOS_BLOCK_SIZE);
PRODOS_SET_INDIRECT_ENTRY(dind_bh->b_data,ind_existing,ind_ptr);
prodos_brelse(ind_bh);
inode->i_blocks = ++new_bused;
}
prodos_brelse(dind_bh);
}
}
{
u16 blk = pi->i_key;
struct buffer_head *bh = NULL;
/* Appropriate action depends upon the file's storage type. */
switch (pi->i_stype) {
case PRODOS_STYPE_TREE:
/* Load double indirect block. */
bh = prodos_bread(inode->i_sb,blk);
if (!bh) {
result = -EIO;
goto out_cleanup;
}
/* Get indirect block and release double indirect block. */
blk = PRODOS_GET_INDIRECT_ENTRY(bh->b_data,block >> 8);
prodos_brelse(bh);
bh = NULL;
/* Fall through. */
case PRODOS_STYPE_SAPLING:
/* Load indirect block. */
bh = prodos_bread(inode->i_sb,blk);
if (!bh) {
result = -EIO;
goto out_cleanup;
}
/* Get data block and release indirect block. */
blk = PRODOS_GET_INDIRECT_ENTRY(bh->b_data,block & 0xff);
if (!blk) {
bh_res->b_state |= (1UL << BH_New);
blk = prodos_alloc_block(inode->i_sb);
if (!blk) {
result = -ENOSPC;
goto out_cleanup;
}
PRODOS_SET_INDIRECT_ENTRY(bh->b_data,block & 0xff,blk);
inode->i_blocks++;
}
prodos_brelse(bh);
bh = NULL;
/* Fall through. */
case PRODOS_STYPE_SEEDLING:
/* Set bh_res fields to cause the block to be read from disk. */
bh_res->b_blocknr = PRODOS_SB(inode->i_sb)->s_part_start + blk;
bh_res->b_dev = inode->i_dev;
bh_res->b_state |= (1 << BH_Mapped);
}
}
mark_inode_dirty(inode);
out_cleanup:
#endif
return result;
}
/*****************************************************************************
* dos33_readpage()
*****************************************************************************/
int dos33_readpage(struct file *filp,struct page *page) {
int result = 0;
DOS33_DEBUG("readpage\n");
/* Let the generic "read page" function do most of the work. */
result = block_read_full_page(page,dos33_get_block);
/* Propagate block_read_full_page() return value. */
return result;
}
/*****************************************************************************
* prodos_writepage()
*****************************************************************************/
int dos33_writepage(struct page *page) {
DOS33_DEBUG("writepage\n");
/* Generic function does the work with the help of a get_block function. */
// PRODOS_ERROR_0(page->mapping->host->i_sb,"called");
// return block_write_full_page(page,prodos_get_block_write);
return 0;
}
/*****************************************************************************
* prodos_prepare_write()
*****************************************************************************/
int dos33_prepare_write(struct file *file,struct page *page,unsigned int from,unsigned int to) {
DOS33_DEBUG("prepare_write\n");
//// return block_prepare_write(page,from,to,prodos_get_block_write);
return 0;
}
/*****************************************************************************
* prodos_commit_write()
*****************************************************************************/
int dos33_commit_write(struct file *file,struct page *page,unsigned int from,unsigned int to) {
DOS33_DEBUG("commit write\n");
#if 0
/* Convert text files to ProDOS format. */
if (PRODOS_I(page->mapping->host)->i_flags & PRODOS_I_CRCONV) {
int i = 0;
char *pdata = kmap(page);
for (i = 0;i < PAGE_CACHE_SIZE;i++,pdata++)
if (*pdata == '\n') *pdata = '\r';
kunmap(page);
}
/* Let generic function do the real work. */
#endif
return generic_commit_write(file,page,from,to);
}
/*****************************************************************************
* prodos_bmap()
*****************************************************************************/
int dos33_bmap(struct address_space *mapping,long block) {
DOS33_DEBUG("bmap\n");
/* Generic function does the work with the help of a get_block function. */
// PRODOS_ERROR_0(mapping->host->i_sb,"called");
// return generic_block_bmap(mapping,block,prodos_get_block_write);
return 0;
}

189
dos33fs-linux2.4/inode.c Normal file
View File

@ -0,0 +1,189 @@
/*****************************************************************************
* inode.c
* Inode operations.
*
* Apple II DOS 3.3 Filesystem Driver for Linux 2.4.x
* Copyright (c) 2001 Vince Weaver
* Copyright (c) 2001 Matt Jensen.
* This program is free software distributed under the terms of the GPL.
*****************************************************************************/
/*= Kernel Includes =========================================================*/
#include <linux/blkdev.h>
/*= DOS 3.3 Includes ========================================================*/
#include "dos33.h"
/*****************************************************************************
* dos33_read_inode()
*****************************************************************************/
void dos33_read_inode(struct inode *inode) {
SHORTCUT struct dos33_inode_info * const pi = DOS33_I(inode);
SHORTCUT struct super_block * const sb = inode->i_sb;
SHORTCUT const int dblk = (DOS33_INO_TRACK(inode->i_ino)*0x10)+
DOS33_INO_SECTOR(inode->i_ino);
int dent=DOS33_INO_ENTRY(inode->i_ino);
struct buffer_head *bh = NULL;
struct dos33_catalog_sector *dir = NULL;
DOS33_DEBUG("read_inodes: inode 0x%08x\n",(int)inode->i_ino);
/* Initialize the inode structure. */
memset(pi,0,sizeof(struct dos33_inode_info));
DOS33_DEBUG("DBLK %x ENTRY %x\n",dblk,dent);
/* Read the directory block containing this entry. */
bh = dos33_bread(sb,dblk);
if (!bh) {
DOS33_ERROR("dos33_bread() failed");
make_bad_inode(inode);
goto out_cleanup;
}
/* Get a pointer to the directory block. */
if (dblk%2) {
dir = (struct dos33_catalog_sector*) (bh->b_data+256);
}
else {
dir = (struct dos33_catalog_sector*)bh->b_data;
}
/* Read a directory inode. */
if (DOS33_INO_DENT(inode->i_ino)) {
DOS33_DEBUG("DIRECTORY\n");
/* Initialize items that are common to all directories. */
pi->i_key = inode->i_ino;
inode->i_op = &dos33_dir_inode_operations;
inode->i_fop = &dos33_dir_operations;
inode->i_mode = S_IFDIR;
inode->i_mtime = inode->i_atime = inode->i_ctime =0;
/* Convert the access flags. */
inode->i_mode |=0777;
inode->i_blocks = 1;
/* Calculate the "size" of the directory. */
inode->i_size = inode->i_blocks << DOS33_BLOCK_SIZE_BITS;
}
/* Read a file inode. */
else {
struct dos33_file_t *file_entry = NULL;
file_entry=&dir->files[dent];
DOS33_DEBUG("FILE inode %x\n",(int)inode->i_ino);
/* Set up stuff that is specific to files. */
pi->i_filetype = file_entry->file_type;
inode->i_op = &dos33_file_inode_operations;
inode->i_fop = &dos33_file_operations;
inode->i_mapping->a_ops = &dos33_address_space_operations;
if (file_entry->file_type &0x80){
inode->i_mode=(S_IFREG|S_IRUGO|S_IXUGO);
}
else {
inode->i_mode=(S_IFREG|S_IRWXUGO);
}
// inode->i_mode = S_IFREG; | prodos_get_mode(ent->access,0);
/* My birthdate */
/* a bit anachronistic, 2 years 6 months before the Disk ][ was available */
inode->i_mtime = 256246800;
inode->i_atime = inode->i_ctime = 256246800;
inode->i_size = le16_to_cpu(file_entry->num_sectors)*256;
inode->i_blocks = le16_to_cpu(file_entry->num_sectors)/2;
}
/* Set up stuff that is common to every type of inode. */
inode->i_nlink = 1;
inode->i_uid = 0; /* root uid (just for now.) */
inode->i_gid = 0; /* root gid (just for now.) */
out_cleanup:
/* Release the directory block. */
dos33_brelse(bh);
bh = NULL;
}
/*****************************************************************************
* prodos_write_inode()
* Write an @inode's metainformation back to disk.
*****************************************************************************/
void dos33_write_inode(struct inode *inode,int unused) {
DOS33_DEBUG("write inodes\n");
#if 0
SHORTCUT struct prodos_inode_info * const pi = PRODOS_I(inode);
struct buffer_head *dir_bh = NULL;
struct prodos_dir_entry *ent = NULL;
u32 eof = cpu_to_le32((u32)inode->i_size);
PRODOS_INFO_1(inode->i_sb,"called for inode 0x%08x",(int)inode->i_ino);
/* XXX: we'll eventually want to modify privileges and time stamps. */
/* Do nothing if the inode is not linked (free.) */
if (!inode->i_nlink) return;
/* Load the directory block and get pointer to this entry. */
dir_bh = prodos_bread(inode->i_sb,PRODOS_INO_DBLK(inode->i_ino));
if (!dir_bh) {
PRODOS_ERROR_0(inode->i_sb,"failed to read directory block");
goto out_cleanup;
}
/* Write a directory inode. */
if (PRODOS_INO_DENT(inode->i_ino) == PRODOS_DENT_DIR) {
struct prodos_dir_block_first *dir = (void*)dir_bh->b_data;
struct buffer_head *parent_bh = NULL;
/* Load and update the parent directory entry. */
parent_bh = prodos_bread(inode->i_sb,le16_to_cpu(dir->u.dir_header.parent_block));
if (!parent_bh) {
PRODOS_ERROR_0(inode->i_sb,"failed to read parent directory block");
goto out_cleanup;
}
ent = &((struct prodos_dir_block*)parent_bh->b_data)->entries[dir->u.dir_header.parent_entry - 1];
memcpy(&ent->eof,&eof,3);
ent->blocks_used = cpu_to_le16(inode->i_blocks);
mark_buffer_dirty(parent_bh);
prodos_brelse(parent_bh);
}
/* Write a file inode. */
else {
/* Update the directory entry. */
ent = &((struct prodos_dir_block*)dir_bh->b_data)->entries[PRODOS_INO_DENT(inode->i_ino)];
memcpy(&ent->eof,&eof,3);
ent->key_block = cpu_to_le16(pi->i_key);
ent->blocks_used = cpu_to_le16(inode->i_blocks);
ent->name[0] = (ent->name[0] & 0x0f) | pi->i_stype;
mark_buffer_dirty(dir_bh);
}
out_cleanup:
if (dir_bh) prodos_brelse(dir_bh);
#endif
}
/*****************************************************************************
* dos33_put_inode()
*****************************************************************************/
void dos33_put_inode(struct inode *inode) {
DOS33_DEBUG("put inodes\n");
DOS33_DEBUG("called on ino 0x%08x",(int)inode->i_ino);
}

84
dos33fs-linux2.4/misc.c Normal file
View File

@ -0,0 +1,84 @@
/*****************************************************************************
* misc.c
* Miscellaneous utility and helper functions.
*
* Apple II DOS 3.3 Filesystem Driver for Linux 2.4.x
* Copyright (c) 2001 Vince Weaver
* Copyright (c) 2001 Matt Jensen.
* This program is free software distributed under the terms of the GPL.
*****************************************************************************/
/*= Kernel Includes =========================================================*/
#include <linux/blkdev.h>
/*= DOS 3.3 Includes =========================================================*/
#include "dos33.h"
extern int dos33_convert_filename(char *filename) {
int i,last_char=0;
for(i=0;i<DOS33_MAX_NAME_LEN;i++) {
filename[i]&=0x7f; /* strip high bit */
if (filename[i]!=0x20) last_char=i;
}
filename[last_char+1]=0;
// printk("%i : \"%s\"\n",last_char,filename);
return last_char+1;
}
/*****************************************************************************
* dos33_check_name()
* Check a name for validity under DOS 3.3 naming rules.
* namely, first character must be > 63
* no commas or colors allowed. Everything else goes
*****************************************************************************/
int dos33_check_name(struct qstr *qstr) {
int len = qstr->len;
int i;
/* Check only up to ProDOS name length limit. */
if (len>DOS33_MAX_NAME_LEN) len=DOS33_MAX_NAME_LEN;
if (qstr->name[0]<64) return -EINVAL;
for(i=0;i<len;i++) {
if ((qstr->name[i]==',') || (qstr->name[i]==':')) return -EINVAL;
}
return 0;
}
/*****************************************************************************
* dos33_bread()
* Read a block from a device.
* do some magic for the 256byte->512byte transition
*****************************************************************************/
struct buffer_head *dos33_bread(struct super_block *sb,int block_num) {
int internal_block_num=block_num/2;
SHORTCUT struct dos33_sb_info * const psb = DOS33_SB(sb);
if (internal_block_num < 0 || internal_block_num >= psb->s_part_size) {
return NULL;
}
DOS33_DEBUG("Attempting to read block 0x%x %i\n",internal_block_num,
psb->s_part_start+internal_block_num);
return bread(sb->s_dev,psb->s_part_start + internal_block_num,DOS33_BLOCK_SIZE);
}
/*****************************************************************************
* dos33_brelse()
* Release a block that was previously read via dos33_bread().
*****************************************************************************/
void dos33_brelse(struct buffer_head *bh) {
brelse(bh);
}

550
dos33fs-linux2.4/super.c Normal file
View File

@ -0,0 +1,550 @@
/*****************************************************************************
* super.c
* Superblock operations and basic interface to the Linux VFS.
*
* Apple II DOS 3.3 Filesystem Driver for Linux 2.4.x
* Copyright (c) 2001 Vince Weaver
* Copyright (c) 2001 Matt Jensen.
* This program is free software distributed under the terms of the GPL.
*****************************************************************************/
/*= Kernel Includes =========================================================*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/blkdev.h>
/*= DOS 3.3 Includes =======================================================*/
#include "dos33.h"
/*= Forward Declarations ====================================================*/
/* For the Linux module interface. */
int __init init_dos33_fs(void);
void __exit exit_dos33_fs(void);
/* For dos33_fs_type. */
struct super_block *dos33_read_super(struct super_block *,void *,int);
/* For dos33_super_operations. */
void dos33_put_super(struct super_block *);
void dos33_write_super(struct super_block *);
int dos33_statfs(struct super_block *,struct statfs *);
/*= VFS Interface Structures ================================================*/
/* Linux module operations. */
EXPORT_NO_SYMBOLS;
module_init(init_dos33_fs)
module_exit(exit_dos33_fs)
/* DOS 3.3 driver metainformation. */
DECLARE_FSTYPE_DEV(dos33_fs_type,"dos33",dos33_read_super);
/* DOS 3.3 superblock operations. */
struct super_operations dos33_super_operations = {
read_inode: dos33_read_inode,
write_inode: dos33_write_inode,
put_inode: dos33_put_inode,
put_super: dos33_put_super,
// write_super: dos33_write_super,
statfs: dos33_statfs
};
/* Number of one bits in a given 4-bit value. */
static int onebits[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
/*= Private Functions =======================================================*/
/*****************************************************************************
* dos33_count_ones()
* Counts the one (set) bits in a block of @data, @size bytes long. This is
* basically the nifty algorithm that is also employed by (and was stolen
* from) the minix fs driver.
*****************************************************************************/
int dos33_count_ones(void *data,size_t size) {
const u32 *bytes = (u32*)data;
u32 ones = 0;
u32 tmp = 0;
DOS33_DEBUG("Count Ones\n");
/* Count one bits, one nibble at a time. */
for(size /= 4;size > 0;size--) {
tmp = *bytes++;
while (tmp) {
ones += onebits[tmp & 0x0f];
tmp >>= 4;
}
}
/* Return the number of ones found. */
return ones;
}
/*****************************************************************************
* dos33_find_first_one()
* Return the position of the first one bit in a block of @data which is @size
* bytes in length. Returns -1 if no one bits were found.
*****************************************************************************/
int dos33_find_first_one(void *data,size_t size) {
// const u32 *bytes = (u32*)data;
// int pos = 0;
// u32 tmp = 0;
DOS33_DEBUG("find_first_one\n");
#if 0
/* Search for a one bit; if found, return its position. */
for (size /= 4;size > 0;size--,bytes++,pos += 32) {
if (*bytes) {
for (tmp = be32_to_cpu(*bytes);!(tmp & 0x80000000);tmp <<= 1,pos++);
return pos;
}
}
/* No one bits were found. */
#endif
return -1;
}
/*****************************************************************************
* prodos_mark_block()
* Modify an entry in the volume bitmap. Note that the bitmap must be locked
* before calling this function.
*****************************************************************************/
void dos33_mark_block(struct super_block *sb,int block,int free) {
// SHORTCUT struct prodos_sb_info *psb = PRODOS_SB(sb);
// SHORTCUT struct buffer_head *bh = psb->s_bm_bh[block / 4096];
// u32 * const data = ((u32*)bh->b_data) + block % 4096 / 32;
// const int bit = cpu_to_be32(0x80000000 >> block % 4096 % 32);
DOS33_DEBUG("mark_block\n");
#if 0
/* Check whether we are to mark the block used or free. */
if (free) {
/* We should only be freeing used blocks. */
if (*data & bit) {
PRODOS_ERROR_1(sb,"block %i is already marked free",block);
return;
}
/* Mark it free. */
*data |= bit;
if (psb->s_bm_free >= 0) psb->s_bm_free++;
}
else {
/* We should only be allocating free blocks. */
if (!(*data & bit)) {
PRODOS_ERROR_1(sb,"block %i is already marked used",block);
return;
}
/* Mark it clear. */
*data &= ~bit;
if (psb->s_bm_free >= 0) psb->s_bm_free--;
}
#endif
/* The bitmap block is now dirty. */
// mark_buffer_dirty(bh);
}
/*****************************************************************************
* prodos_parse_options()
* Parse the mount options string and fill prodos_sb_info fields accordingly.
*****************************************************************************/
int dos33_parse_options(struct super_block *sb,char *opts) {
// SHORTCUT struct prodos_sb_info * const psb = PRODOS_SB(sb);
// char *arg_key = NULL;
// char *arg_value = NULL;
DOS33_DEBUG("parse_options\n");
#if 0
/* Step through "key[=value]" options, modifying members of psb */
if (!opts) return 1;
for (arg_key = strtok(opts,",");arg_key;arg_key = strtok(NULL,",")) {
if ((arg_value = strchr(arg_key,'='))) *arg_value++ = 0;
if (!strcmp(arg_key,"verbose")) psb->s_flags |= PRODOS_FLAG_VERBOSE;
else if (!strcmp(arg_key,"crconv")) psb->s_flags |= PRODOS_FLAG_CONVERT_CR;
else if (!strcmp(arg_key,"case")) {
if (arg_value) {
if (!strcmp(arg_value,"lower"))
psb->s_flags |= PRODOS_FLAG_LOWERCASE;
else if (strcmp(arg_value,"asis")) goto out_invalid_value;
}
else goto out_omitted_value;
}
else if (!strcmp(arg_key,"forks")) {
if (arg_value) {
if (!strcmp(arg_value,"show"))
psb->s_flags |= PRODOS_FLAG_SHOW_FORKS;
else if (strcmp(arg_value,"hide")) goto out_invalid_value;
}
else goto out_omitted_value;
}
else if (!strcmp(arg_key,"partition") || !strcmp(arg_key,"part")) {
if (arg_value) strncpy(psb->s_part,arg_value,32);
else goto out_omitted_value;
}
else goto out_invalid_key;
}
/* Success. */
return ~0;
out_omitted_value:
PRODOS_ERROR_1(sb,"option \"%s\" requires a value",arg_key);
goto out_error;
out_invalid_value:
PRODOS_ERROR_2(sb,"option \"%s\" given unrecognized value \"%s\"",arg_key,arg_value);
goto out_error;
out_invalid_key:
PRODOS_ERROR_1(sb,"unrecognized option \"%s\"",arg_key);
goto out_error;
out_error:
#endif
return 0;
}
/*= Exported Functions ======================================================*/
/*****************************************************************************
* dos33_count_free_blocks()
* Count free blocks on the volume by counting the one bits in the volume
* bitmap.
*****************************************************************************/
int dos33_count_free_blocks(struct super_block *sb) {
SHORTCUT struct dos33_sb_info * const psb = DOS33_SB(sb);
DOS33_DEBUG("Count_free_blocks\n");
/* Grab the bitmap lock. */
down(&psb->s_bm_lock);
/* Count free blocks if they have not already been counted. */
if (psb->s_bm_free < 0) {
psb->s_bm_free = 0;
psb->s_bm_free += (dos33_count_ones(&(psb->bitmaps[0]),0x23))/2;
}
/* Release the bitmap lock and return free block count. */
up(&psb->s_bm_lock);
return psb->s_bm_free;
}
/*****************************************************************************
* prodos_alloc_block()
* Find the first free block on the volume, mark it used, and return its
* index.
*****************************************************************************/
int dos33_alloc_block(struct super_block *sb) {
// SHORTCUT struct prodos_sb_info * const psb = PRODOS_SB(sb);
int result = -ENOSPC;
// int pos = -1;
// int i = 0;
DOS33_DEBUG("alloc_block\n");
#if 0
/* Grab the bitmap lock. */
down(&psb->s_bm_lock);
/* Fail early if we already know that all blocks are full. */
if (!psb->s_bm_free) goto out_cleanup;
/* Find first one bit in the bitmap, which signifies a free block. */
for (i = 0;psb->s_bm_bh[i];i++) {
pos = prodos_find_first_one(psb->s_bm_bh[i]->b_data,PRODOS_BLOCK_SIZE);
if (pos != -1) {
pos += (i * 4096);
break;
}
}
/* XXX: should probably cache first free block index. */
/* If a bit was found, clear it. */
if (pos >= 0 && pos < psb->s_part_size) {
prodos_mark_block(sb,pos,0);
result = pos;
}
out_cleanup:
up(&psb->s_bm_lock);
#endif
return result;
}
/*****************************************************************************
* prodos_free_block()
* Mark a block as free by setting its bit in the volume bitmap.
*****************************************************************************/
int dos33_free_block(struct super_block *sb,u16 block) {
DOS33_DEBUG("free_blocks\n");
#if 0
/* Grab the bitmap lock. */
down(&PRODOS_SB(sb)->s_bm_lock);
/* Set the bit. */
prodos_mark_block(sb,block,1);
/* Release the lock and return. */
up(&PRODOS_SB(sb)->s_bm_lock);
#endif
return 0;
}
/*****************************************************************************
* prodos_free_tree_blocks()
* Mark all blocks in a tree (file or fork; seedling, sapling, or full tree)
* as free.
*****************************************************************************/
int prodos_free_tree_blocks(struct super_block *sb,u8 stype,u16 key_block,u16 blocks_used) {
int result = 0;
// struct buffer_head *dind_bh = NULL;
// u16 ind_block = 0;
// struct buffer_head *ind_bh = NULL;
DOS33_DEBUG("free_tree_blocks\n");
#if 0
/* Grab the bitmap lock. */
down(&PRODOS_SB(sb)->s_bm_lock);
/* Free blocks in sapling and tree files. */
if (stype != PRODOS_STYPE_SEEDLING) {
int i = 0;
u16 block = 0;
/* Load the double indirect block for tree files. */
if (stype == PRODOS_STYPE_TREE) {
dind_bh = prodos_bread(sb,key_block);
if (!dind_bh) {
result = -EIO;
goto out_cleanup;
}
/* Allow for double indirect to be freed outside the loop. */
blocks_used--;
}
/* Release all data blocks and indirect blocks. */
while (blocks_used) {
/* Get next indirect block when necessary. */
if (!(i % 256)) {
ind_block = dind_bh ?
PRODOS_GET_INDIRECT_ENTRY(dind_bh->b_data,i / 256) :
key_block;
ind_bh = prodos_bread(sb,ind_block);
if (!ind_bh) {
result = -EIO;
goto out_cleanup;
}
}
/* Free next data block (if it isn't sparse.) */
block = PRODOS_GET_INDIRECT_ENTRY(ind_bh->b_data,i % 256);
if (block) {
prodos_mark_block(sb,block,1);
blocks_used--;
}
/* Free indirect block when necessary. */
if (!(++i % 256) || (blocks_used == 1)) {
prodos_brelse(ind_bh);
ind_bh = NULL;
prodos_mark_block(sb,ind_block,1);
blocks_used--;
}
}
/* Free the double indirect block for tree files. */
if (stype == PRODOS_STYPE_TREE) {
prodos_brelse(dind_bh);
dind_bh = NULL;
prodos_mark_block(sb,key_block,1);
}
}
/* Free blocks in seedling files. */
else prodos_mark_block(sb,key_block,1);
out_cleanup:
if (ind_bh) prodos_brelse(ind_bh);
if (dind_bh) prodos_brelse(dind_bh);
up(&PRODOS_SB(sb)->s_bm_lock);
#endif
return result;
}
/*= Interface Functions =====================================================*/
/*****************************************************************************
* dos33_read_super()
*****************************************************************************/
struct super_block *dos33_read_super(struct super_block *sb,void *opts,int silent) {
SHORTCUT kdev_t const dev = sb->s_dev;
struct dos33_sb_info *psb = NULL;
struct buffer_head *bh = NULL;
struct dos33_vtol *pdbf = NULL;
struct inode *root_inode = NULL;
u16 i = 0;
DOS33_DEBUG("read_super\n");
/* Initialize the device and the super_block struct. */
set_blocksize(dev,DOS33_BLOCK_SIZE);
sb->s_magic = DOS33_SUPER_MAGIC;
sb->s_op = &dos33_super_operations;
sb->s_blocksize = DOS33_BLOCK_SIZE;
sb->s_blocksize_bits = DOS33_BLOCK_SIZE_BITS;
sb->s_maxbytes = DOS33_MAX_FILE_SIZE;
sb->s_flags = MS_RDONLY | MS_NOSUID;
/* Allocate the DOS 3.3 superblock metainformation struct. */
psb = kmalloc(sizeof(struct dos33_sb_info),GFP_KERNEL);
if (!psb) {
DOS33_ERROR("failed to allocate memory for prodos_sb_info");
goto out_error;
}
DOS33_SB(sb) = psb;
/* Fill the superblock metainformation struct with default values. */
memset(DOS33_SB(sb),0,sizeof(struct dos33_sb_info));
psb->s_part_size = blk_size[MAJOR(dev)] ? blk_size[MAJOR(dev)][MINOR(dev)] * 2 : 0;
init_MUTEX(&psb->s_bm_lock);
init_MUTEX(&psb->s_dir_lock);
/* Parse mount options and, if necessary, find desired partition. */
// if (!prodos_parse_options(sb,(char*)opts)) goto out_error;
/* Load DOS 3.3 volume directory block. */
bh = dos33_bread(sb,DOS33_VOLUME_DIR_BLOCK);
if (!bh) {
DOS33_ERROR("failed to read volume directory block");
goto out_error;
}
pdbf = (struct dos33_vtol*)bh->b_data;
/* Check for DOS 3.3 footprint in the block. */
/* this is a possibly-bogus check, replace */
/* if (pdbf->four != 0x4) {
DOS33_ERROR("failed to find a DOS 3.3 filesystem");
goto out_error;
}
*/
/* Use size from the volume directory as partition size. */
psb->s_part_size = ((pdbf->tracks_per_disk*pdbf->sectors_per_track*le16_to_cpu(pdbf->bytes_per_sector))/512);
/* Initialize the volume bitmap stuff. */
psb->s_bm_free = -1;
for(i=0;i<pdbf->tracks_per_disk;i++) {
psb->bitmaps[i]=cpu_to_le32(pdbf->bitmaps[i]);
}
printk("dos33.o: found %ik DOS 3.%i filesystem, Volume %i\n",
psb->s_part_size/2,pdbf->dos_version,pdbf->volume);
/* Get root inode. */
root_inode = iget(sb,DOS33_MAKE_INO(1,0,DOS33_VOLUME_DIR_TRACK,0xf));
sb->s_root = d_alloc_root(root_inode);
if (!sb->s_root) {
DOS33_ERROR("failed to get root inode");
goto out_error;
}
sb->s_root->d_op = &dos33_dentry_operations;
/* Return a copy of the 'sb' pointer on success. */
return sb;
out_error:
if (sb->s_root) {
iput(root_inode);
root_inode = NULL;
}
if (bh) {
dos33_brelse(bh);
bh = NULL;
}
if (psb) {
kfree(DOS33_SB(sb));
DOS33_SB(sb) = NULL;
}
return NULL;
}
/*****************************************************************************
* prodos_put_super()
*****************************************************************************/
void dos33_put_super(struct super_block *sb) {
SHORTCUT struct dos33_sb_info * const psb = DOS33_SB(sb);
// int i = 0;
DOS33_DEBUG("put_super\n");
#if 0 /* Release volume bitmap blocks. */
for (i = 0;psb->s_bm_bh[i];i++) {
prodos_brelse(psb->s_bm_bh[i]);
psb->s_bm_bh[i] = NULL;
}
#endif
/* Release the ProDOS super block metainformation structure. */
kfree(psb);
}
/*****************************************************************************
* prodos_write_super()
*****************************************************************************
void prodos_write_super(struct super_block *sb) {
}*/
/*****************************************************************************
* prodos_statfs()
*****************************************************************************/
int dos33_statfs(struct super_block *sb,struct statfs *statfs) {
SHORTCUT struct dos33_sb_info * const psb = DOS33_SB(sb);
DOS33_DEBUG("statfs\n");
/* Copy applicable information. */
statfs->f_type = DOS33_SUPER_MAGIC;
statfs->f_bsize = sb->s_blocksize;
statfs->f_blocks = psb->s_part_size;
statfs->f_bfree = dos33_count_free_blocks(sb);
statfs->f_bavail = statfs->f_bfree;
return 0;
}
/*= Module Functions ========================================================*/
/*****************************************************************************
* init_dos33_filesystem()
*****************************************************************************/
int __init init_dos33_fs(void) {
/* Since we are overlaying our prodos_inode_info structure over a
minix_inode_info structure, we should verify that the former is no larger
than the latter. */
DOS33_DEBUG("Insmodding\n");
if (sizeof(struct dos33_inode_info) > sizeof(struct minix_inode_info)) {
DOS33_ERROR("aborting; struct prodos_inode_info too big!");
return -EFAULT;
}
/* Register the filesystem. */
return register_filesystem(&dos33_fs_type);
}
/*****************************************************************************
* exit_dos33_filesystem()
*****************************************************************************/
void __exit exit_dos33_fs(void) {
/* Unregister the filesystem. */
DOS33_DEBUG("Rmmodding\n");
unregister_filesystem(&dos33_fs_type);
}