mirror of
https://github.com/deater/dos33fsprogs.git
synced 2024-12-24 13:32:23 +00:00
Add dos33fs code
This was a dos33fs filesystem driver for Linux 2.4 It is included for historical reasons.
This commit is contained in:
parent
0dfcfcd5bd
commit
4f96a4e326
3
dos33fs-linux2.4/BUGS
Normal file
3
dos33fs-linux2.4/BUGS
Normal 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
11
dos33fs-linux2.4/CHANGES
Normal 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
356
dos33fs-linux2.4/COPYING
Normal 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
19
dos33fs-linux2.4/CREDITS
Normal 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
21
dos33fs-linux2.4/Makefile
Normal 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
134
dos33fs-linux2.4/README
Normal 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
2
dos33fs-linux2.4/TODO
Normal file
@ -0,0 +1,2 @@
|
||||
* R/W support
|
||||
* support for metadata
|
92
dos33fs-linux2.4/dentry.c
Normal file
92
dos33fs-linux2.4/dentry.c
Normal 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
593
dos33fs-linux2.4/dir.c
Normal 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
148
dos33fs-linux2.4/dos33.h
Normal 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
|
48
dos33fs-linux2.4/dos33_fs.h
Normal file
48
dos33fs-linux2.4/dos33_fs.h
Normal 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
491
dos33fs-linux2.4/file.c
Normal 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
189
dos33fs-linux2.4/inode.c
Normal 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
84
dos33fs-linux2.4/misc.c
Normal 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
550
dos33fs-linux2.4/super.c
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user