From cbb96659ea274f612c178abcf3abe8de4298e55f Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 3 Mar 2009 19:29:23 -0800 Subject: auto import from //depot/cupcake/@135843 --- Android.mk | 3 + COPYING | 674 ++++++++++++++ ChangeLog | 345 ++++++++ Makefile | 112 +++ NOTICE | 674 ++++++++++++++ debian/changelog | 427 +++++++++ debian/compat | 1 + debian/control | 35 + debian/copyright | 88 ++ debian/doc/HISTORY | 20 + debian/docs | 1 + debian/patches/14-bootcode.dpatch | 235 +++++ debian/rules | 46 + doc/ANNOUNCE.mkdosfs | 41 + doc/ChangeLog.dosfsck | 10 + doc/ChangeLog.dosfstools-2.x | 161 ++++ doc/ChangeLog.mkdosfs | 18 + doc/README.dosfsck | 60 ++ doc/README.dosfstools-2.x | 60 ++ doc/README.mkdosfs | 50 ++ doc/TODO.dosfstools-2.x | 14 + man/dosfsck.8 | 147 ++++ man/dosfslabel.8 | 53 ++ man/mkdosfs.8 | 211 +++++ src/Android.mk | 20 + src/boot.c | 463 ++++++++++ src/boot.h | 31 + src/check.c | 883 +++++++++++++++++++ src/check.h | 40 + src/common.c | 125 +++ src/common.h | 57 ++ src/dosfsck.c | 207 +++++ src/dosfsck.h | 220 +++++ src/dosfslabel.c | 126 +++ src/fat.c | 381 ++++++++ src/fat.h | 81 ++ src/file.c | 263 ++++++ src/file.h | 72 ++ src/io.c | 209 +++++ src/io.h | 71 ++ src/lfn.c | 495 +++++++++++ src/lfn.h | 36 + src/mkdosfs.c | 1761 +++++++++++++++++++++++++++++++++++++ src/version.h | 28 + 44 files changed, 9055 insertions(+) create mode 100644 Android.mk create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 Makefile create mode 100644 NOTICE create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/doc/HISTORY create mode 100644 debian/docs create mode 100644 debian/patches/14-bootcode.dpatch create mode 100755 debian/rules create mode 100644 doc/ANNOUNCE.mkdosfs create mode 100644 doc/ChangeLog.dosfsck create mode 100644 doc/ChangeLog.dosfstools-2.x create mode 100644 doc/ChangeLog.mkdosfs create mode 100644 doc/README.dosfsck create mode 100644 doc/README.dosfstools-2.x create mode 100644 doc/README.mkdosfs create mode 100644 doc/TODO.dosfstools-2.x create mode 100644 man/dosfsck.8 create mode 100644 man/dosfslabel.8 create mode 100644 man/mkdosfs.8 create mode 100644 src/Android.mk create mode 100644 src/boot.c create mode 100644 src/boot.h create mode 100644 src/check.c create mode 100644 src/check.h create mode 100644 src/common.c create mode 100644 src/common.h create mode 100644 src/dosfsck.c create mode 100644 src/dosfsck.h create mode 100644 src/dosfslabel.c create mode 100644 src/fat.c create mode 100644 src/fat.h create mode 100644 src/file.c create mode 100644 src/file.h create mode 100644 src/io.c create mode 100644 src/io.h create mode 100644 src/lfn.c create mode 100644 src/lfn.h create mode 100644 src/mkdosfs.c create mode 100644 src/version.h diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..3c3cb61 --- /dev/null +++ b/Android.mk @@ -0,0 +1,3 @@ +ifneq ($(TARGET_SIMULATOR),true) + include $(call all-subdir-makefiles) +endif diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. 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 +them 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 prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. 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. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey 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; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + 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. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +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. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + 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 +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 3 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, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program 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, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU 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 Lesser General +Public License instead of this License. But first, please read +. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..4a53630 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,345 @@ +commit 41574812a2586f0b6aa1d4f6e2276e557e9cbbcf +Author: Daniel Baumann +Date: Sun Nov 23 18:41:01 2008 +0100 + + Applying Fedoras dosfstools-vfat-timingfix.diff from Bill Nottingham + to fix vfat timing issue. See + https://bugzilla.redhat.com/show_bug.cgi?id=448247 for more information. + +commit b80656109cc5cffdefd626c2ec9d45e3cf63a03e +Author: Ulrich Mueller +Date: Tue Oct 7 07:55:37 2008 +0200 + + Patch to check for bad number of clusters in dosfsck: + + * FAT16 filesystems with 65525 clusters or more will be rejected + (Before, this was not tested for. Up to 65535 clusters were accepted + as good). + + * For FAT32 filesystems with less than 65525 a warning message will be + output. + + Macro MSDOS_FAT12 is now replaced by FAT12_THRESHOLD to make it + consistent with the definition in mkdosfs and to remove the dependency + on the kernel version. + +commit b9c13d143c420a3ec6e1dcb652cafa407621e9c7 +Author: Dann Frazier +Date: Tue Sep 30 07:25:19 2008 +0200 + + Changing some wording to make the indended meaning of "full-disk device" + more obvious. + +commit 4df18ad463f41ae368c3c51bfb5a033072605663 +Author: Daniel Baumann +Date: Sun Sep 28 11:43:19 2008 +0200 + + Releasing upstream version 3.0.0. + +commit 17fbf2a6dc9255a6bb832472ae7cda674b55e961 +Author: Daniel Baumann +Date: Sun Sep 28 11:29:01 2008 +0200 + + Adding GPL headers to all files. + +commit d2039e12c8d53472411c91eb8e7a7c0544e13d6d +Author: Daniel Baumann +Date: Sun Sep 28 10:51:55 2008 +0200 + + Adding new GPL license file. + +commit e4e457f4b57090ecf0539f48dc682ab9afd14ab8 +Author: Daniel Baumann +Date: Fri Sep 26 23:31:12 2008 +0200 + + Redoing Makefile from scratch. + +commit 216568ca3a01ed38962b22c7bf838d15d5a4d98d +Author: Daniel Baumann +Date: Sat Sep 27 00:17:38 2008 +0200 + + Removing whitespaces in all files at EOL and EOF. + +commit f59157e06561c525605279145057361afa721042 +Author: Daniel Baumann +Date: Fri Sep 26 23:48:56 2008 +0200 + + Adding Debians dosfslabel.8 manpage from Francois Wendling + . + +commit c1bacab212d2b7f6ea93914976cb60056ff8276d +Author: Daniel Baumann +Date: Fri Sep 26 18:36:04 2008 +0200 + + Updating version.h includes to new location of version.h file. + +commit 1dae9f522062037d3539cadf344e0359c644171f +Author: Daniel Baumann +Date: Fri Sep 26 18:19:36 2008 +0200 + + Removing old lsm file. + +commit d843bec0b987f5582fe048f70e42df18c34d3ae4 +Author: Daniel Baumann +Date: Fri Sep 26 18:07:47 2008 +0200 + + Removing old cvsignore files. + +commit 77fddbc03016752286b26913c62b98f86ee63211 +Author: Daniel Baumann +Date: Fri Sep 26 18:18:39 2008 +0200 + + Removing old build file. + +commit f3e7168fc9eb6f32a6c85021186d84944cefeba8 +Author: Daniel Baumann +Date: Fri Sep 26 18:19:16 2008 +0200 + + Removing old GPL license files. + +commit 68089477036e97911791516ee2167286f26ff819 +Author: Daniel Baumann +Date: Fri Sep 26 18:21:57 2008 +0200 + + Unifying dosfsck and mkdosfs Makefiles in common src/Makefile. + +commit 9432a02d6e7c38872d7b1042f1b8be1b24a57427 +Author: Daniel Baumann +Date: Fri Sep 26 18:04:02 2008 +0200 + + Unifying dosfsck and mkdosfs sources in common src directory. + +commit 0c179b9ee47174d0f34d9fc796d540012740ac01 +Author: Daniel Baumann +Date: Fri Sep 26 18:05:27 2008 +0200 + + Unifying dosfsck and mkdosfs manpages in common man directory. + +commit 2d246c28ba6cfd43be2e44b11283891d922f352b +Author: Daniel Baumann +Date: Fri Sep 26 18:12:29 2008 +0200 + + Unifying dosfsck and mkdosfs documents in common doc directory. + +commit e5b16990515d0214fd103dd8aa22ff6a3cda4b64 +Author: Daniel Baumann +Date: Fri Sep 26 15:39:51 2008 +0200 + + Applying Gentoos dosfstools-2.11-preen.patch from Roy Marples + to alias dosfsck -p to -a: + + * Map -p to -a for baselayout-2, #177514. + +commit 6a1d974251a9f9a142775ace3a8048149abfa90c +Author: Daniel Baumann +Date: Fri Sep 26 15:49:43 2008 +0200 + + Applying Gentoos dosfstools-2.11-build.patch from Mike Frysinger + to improve Makefile: + + * Respect user settings #157785/#157786 by Diego Petteno. + +commit 1ea49f00e61b554dc833d44e1a3617e923be667e +Author: Daniel Baumann +Date: Fri Sep 26 15:37:34 2008 +0200 + + Applying Gentoos dosfstools-2.11-verify-double-count-fix.patch from + Robin H. Johnson to fix double count of files + during verification: + + * Don't double-count n_files during a verification pass. + Bugzilla: http://bugs.gentoo.org/show_bug.cgi?id=99845 + +commit 2d2f20b2c495fa620c7bb3ec5a0838b08f65ab05 +Author: Daniel Baumann +Date: Fri Sep 26 15:33:36 2008 +0200 + + Applying Gentoos dosfstools-2.11-fat32size.patch from Mike Frysinger + to fix generation of filesystems on 256meg devices: + + * Fix generation of FAT filesystems on devices that are 256meg in size + Patch by Ulrich Mueller and accepted upstream + http://bugs.gentoo.org/112504 + +commit a86564a9317b2bf9f7734feacdce794f20af74a7 +Author: Daniel Baumann +Date: Fri Sep 26 15:22:06 2008 +0200 + + Applying Suses dosfstools-2.11-unsupported-sector-size.patch from Petr + Gajdos to add sector size warning: + + * added warning for creation msdos on filesystem with sector size + greater than 4096 [fate#303325] + +commit 8171e51f4e02bd9f92bb515ca7896d3cb1b564b5 +Author: Daniel Baumann +Date: Fri Sep 26 15:18:35 2008 +0200 + + Applying Suses dosfstools-2.11-mkdosfs-geo0.diff from Ludwig Nussel + to fix handling of zero heads and sectors: + + * the HDIO_GETGEO ioctl works on device mapper devices but returns + zero heads and sectors. Therefore let's a) assume dummy values in + that case in mkdosfs and b) don't consider such fat file systems as + invalid in dosfsck. The Linux kernel accepts them anyways. + +commit db887df619f4e995db0ab112334f31464a03fa0e +Author: Daniel Baumann +Date: Fri Sep 26 15:15:40 2008 +0200 + + Applying Suses dosfstools-2.11-linuxfs.patch from Ruediger Oertel + to not include linux/fs.h. + +commit 7fe3fa643494b26962d542fac38d988ac60f8c09 +Author: Daniel Baumann +Date: Fri Sep 26 15:11:50 2008 +0200 + + Applying Fedoras dosfstools-2.11-assumeKernel26.patch from Peter Vrabec + to remove linux 2.6 conditionals: + + * LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) does not work with + glibc-kernheaders-2.4-9.1.94 + +commit 90c1c93c100722a03e48be51b1312fe65c1cb156 +Author: Daniel Baumann +Date: Fri Sep 26 15:05:00 2008 +0200 + + Applying Debians 99-conglomeration.dpatch (no other information + available). + +commit bb6541bf4735e3a7f1c71b4722c6d03bb4549eea +Author: Daniel Baumann +Date: Fri Sep 26 14:26:41 2008 +0200 + + Applying Debians 15-manpage-files.dpatch from Daniel Baumann + to improve dosfsck manpage: + + * Lists fsckNNNN.rec files in FILES section (Closes: #444596). + +commit 49282165866be19d3bc54a3f4bdee2cf3a63ba6c +Author: Daniel Baumann +Date: Fri Sep 26 14:34:42 2008 +0200 + + Applying Debians 13-getopt.dpatch from Adonikam Virgo + to fix mkdosfs getopt: + + * Fixes backup sector getopt (Closes: #232387, #479794). + +commit c32e44b85f4eac6f6a94bd620eea4abba257042a +Author: Daniel Baumann +Date: Fri Sep 26 14:34:17 2008 +0200 + + Applying Debians 12-zero-slot.dpatch by Karl Tomlinson + to fix dosfsck zero slot crashes: + + * Fixes crashes due to zero slot numbers causing a negative offset in + the call to copy_lfn_part in lfn_add_slot. On amd64 this results in + a SIGSEGV in copy_lfn_part. On x86 the result is heap corruption + and thus sometimes a SIGSEGV or double free abort later. (Closes: + #152550, #353198, #356377, #401798). + +commit 370847af533e628aa9e38710e6d50af09f2b71ba +Author: Daniel Baumann +Date: Fri Sep 26 14:33:54 2008 +0200 + + Applying Debians 11-memory-efficiency.dpatch from Eero Tamminen + to improve dosfsck memory efficiency: + + * Improves memory efficiency when checking filesystems. + +commit 28da9f286a52acec7df7ad06cb0679e5f828e7f3 +Author: Daniel Baumann +Date: Fri Sep 26 14:33:28 2008 +0200 + + Applying Debians 10-manpage-synopsis.dpatch from Daniel Baumann + to fix manpage synopsis: + + * List alternative binary names in manpage synopsis (Closes: #284983). + +commit f253073021551c9b58d0f2ac262deb3c1b950b06 +Author: Daniel Baumann +Date: Fri Sep 26 14:32:46 2008 +0200 + + Applying Debians 09-manpage-fat32.dpatch from Daniel Baumann + to improve mkdosfs manpage: + + * Don't claim that FAT32 is not choosed automatically (Closes: + #414183). + +commit f37c07aec3972cfc0db374d544ee3b27c0b4b20b +Author: Daniel Baumann +Date: Fri Sep 26 14:32:23 2008 +0200 + + Applying Debians 08-manpage-drop.dpatch from Daniel Baumann + to improve dosfsck manpage: + + * Don't use confusing word 'drop' when 'delete' is meant (Closes: + #134100). + +commit 3f970c65586da2f44d2a49b639e89341bbaf1fba +Author: Daniel Baumann +Date: Fri Sep 26 14:31:50 2008 +0200 + + Applying Debians 07-manpage-spelling.dpatch from Justin Pryzby + to fix mkdosfs manpage typos. + +commit 18678ba5f3a10c2a54ffee735651d7a265ae7d54 +Author: Daniel Baumann +Date: Fri Sep 26 14:30:31 2008 +0200 + + Applying Suses dosfstools-2.11_determine-sector-size.patch from Petr + Gajdos to determine mkdosfs sector size automatically: + + * determine sector size of device automatically or if -S parameter + present, verify, that it's not under physical sector size + +commit 29753931b078856d78f473cfb6273e111a26891e +Author: Daniel Baumann +Date: Fri Sep 26 14:30:03 2008 +0200 + + Applying Suses dosfstools-2.11-o_excl.patch from Pavol Rusnak + to use O_EXCL in mkdosfs: + + * mkdosfs now opens device with O_EXCL [#238687] + +commit 16bb7b09ad9eaf0fe37a732cabcdbdf975b77d3e +Author: Daniel Baumann +Date: Fri Sep 26 14:29:36 2008 +0200 + + Applying Debians 04-unaligned-memory.dpatch from Khalid Aziz + to fix dosfsck unaligned memory accesses: + + * Fix unaligned memory accesses which cause warnings to appear + everytime the elilo bootloader script runs. This has led a number + of users to believe their install has failed (Closes: #258839). + +commit 1298cc8f37eaa27ca542b8b7186ea5a47a63cd7e +Author: Daniel Baumann +Date: Fri Sep 26 13:47:40 2008 +0200 + + Applying Fedoras dosfstools-2.11-label.patch from Jeremy Katz + to add dosfslabel (originally by Peter Jones). + +commit d23890e1d89770d6d2ba58362c2fc4ebafbde15c +Author: Daniel Baumann +Date: Fri Sep 26 13:41:14 2008 +0200 + + Applying Fedoras dosfstools-2.11-fortify.patch from Jakub Jelinek + to make it build with -D_FORTIFY_SOURCE=2: + + * This violates -D_FORTIFY_SOURCE=2 (which is stricter than C + standard), but isn't actually any buffer overflow. But using memcpy + is more efficient anyway. + +commit 7dbd82000e59246c1c2f8c280c4491259e10a767 +Author: Daniel Baumann +Date: Fri Sep 26 13:40:47 2008 +0200 + + Applying Fedoras dosfstools-2.7-argfix.patch (no other information + available). + +commit 88f3b3139c72ac11cb3dd3f5afa8dbb2198a8de5 +Author: Daniel Baumann +Date: Thu Jun 26 12:45:36 2008 +0200 + + Adding upstream version 2.11. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..148b53a --- /dev/null +++ b/Makefile @@ -0,0 +1,112 @@ +# Makefile +# +# Copyright (C) 2008 Daniel Baumann +# +# 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 3 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, see . +# +# On Debian systems, the complete text of the GNU General Public License +# can be found in /usr/share/common-licenses/GPL-3 file. + +DESTDIR = +PREFIX = /usr/local +SBINDIR = $(PREFIX)/sbin +DOCDIR = $(PREFIX)/share/doc +MANDIR = $(PREFIX)/share/man + +#OPTFLAGS = -O2 -fomit-frame-pointer -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 +OPTFLAGS = -O2 -fomit-frame-pointer $(shell getconf LFS_CFLAGS) +#WARNFLAGS = -Wall -pedantic -std=c99 +WARNFLAGS = -Wall +DEBUGFLAGS = -g +CFLAGS += $(OPTFLAGS) $(WARNFLAGS) $(DEBUGFLAGS) + +VPATH = src + +all: build + +build: dosfsck dosfslabel mkdosfs + +dosfsck: boot.o check.o common.o fat.o file.o io.o lfn.o dosfsck.o + +dosfslabel: boot.o check.o common.o fat.o file.o io.o lfn.o dosfslabel.o + +mkdosfs: mkdosfs.o + +rebuild: distclean build + +install: install-bin install-doc install-man + +install-bin: build + install -d -m 0755 $(DESTDIR)/$(SBINDIR) + install -m 0755 dosfsck dosfslabel mkdosfs $(DESTDIR)/$(SBINDIR) + + ln -sf dosfsck $(DESTDIR)/$(SBINDIR)/fsck.msdos + ln -sf dosfsck $(DESTDIR)/$(SBINDIR)/fsck.vfat + ln -sf mkdosfs $(DESTDIR)/$(SBINDIR)/mkfs.msdos + ln -sf mkdosfs $(DESTDIR)/$(SBINDIR)/mkfs.vfat + +install-doc: + install -d -m 0755 $(DESTDIR)/$(DOCDIR)/dosfstools + install -m 0644 doc/* $(DESTDIR)/$(DOCDIR)/dosfstools + +install-man: + install -d -m 0755 $(DESTDIR)/$(MANDIR)/man8 + install -m 0644 man/*.8 $(DESTDIR)/$(MANDIR)/man8 + + ln -sf dosfsck.8 $(DESTDIR)/$(MANDIR)/man8/fsck.msdos.8 + ln -sf dosfsck.8 $(DESTDIR)/$(MANDIR)/man8/fsck.vfat.8 + ln -sf mkdosfs.8 $(DESTDIR)/$(MANDIR)/man8/mkfs.msdos.8 + ln -sf mkdosfs.8 $(DESTDIR)/$(MANDIR)/man8/mkfs.vfat.8 + +uninstall: uninstall-bin uninstall-doc uninstall-man + +uninstall-bin: + rm -f $(DESTDIR)/$(SBINDIR)/dosfsck + rm -f $(DESTDIR)/$(SBINDIR)/dosfslabel + rm -f $(DESTDIR)/$(SBINDIR)/mkdosfs + + rm -f $(DESTDIR)/$(SBINDIR)/fsck.msdos + rm -f $(DESTDIR)/$(SBINDIR)/fsck.vfat + rm -f $(DESTDIR)/$(SBINDIR)/mkfs.msdos + rm -f $(DESTDIR)/$(SBINDIR)/mkfs.vfat + + rmdir --ignore-fail-on-non-empty $(DESTDIR)/$(SBINDIR) + +uninstall-doc: + rm -rf $(DESTDIR)/$(DOCDIR)/dosfstools + + rmdir --ignore-fail-on-non-empty $(DESTDIR)/$(DOCDIR) + +uninstall-man: + rm -f $(DESTDIR)/$(MANDIR)/man8/dosfsck.8 + rm -f $(DESTDIR)/$(MANDIR)/man8/dosfslabel.8 + rm -f $(DESTDIR)/$(MANDIR)/man8/mkdosfs.8 + + rm -f $(DESTDIR)/$(MANDIR)/man8/fsck.msdos.8 + rm -f $(DESTDIR)/$(MANDIR)/man8/fsck.vfat.8 + rm -f $(DESTDIR)/$(MANDIR)/man8/mkfs.msdos.8 + rm -f $(DESTDIR)/$(MANDIR)/man8/mkfs.vfat.8 + + rmdir --ignore-fail-on-non-empty $(DESTDIR)/$(MANDIR)/man8 + rmdir --ignore-fail-on-non-empty $(DESTDIR)/$(MANDIR) + +reinstall: distclean install + +clean: + rm -f *.o + +distclean: clean + rm -f dosfsck dosfslabel mkdosfs + +.PHONY: build rebuild install install-bin install-doc install-man uninstall uninstall-bin uninstall-doc uninstall-man reinstall clean distclean diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/NOTICE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. 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 +them 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 prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. 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. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey 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; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + 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. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +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. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + 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 +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 3 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, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program 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, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU 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 Lesser General +Public License instead of this License. But first, please read +. diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..0aa9676 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,427 @@ +dosfstools (3.0.1-1) unstable; urgency=low + + * Replacing obsolete dh_clean -k with dh_prep. + * Merging upstream version 3.0.1: + - Changing some wording to make the indended meaning of "full-disk device" + more obvious (Closes: #500623). + + -- Daniel Baumann Sun, 23 Nov 2008 22:51:46 +0100 + +dosfstools (3.0.0-1) unstable; urgency=low + + * Merging upstream version 3.0.0. + * Updating homepage field in control. + * Updating upstream information in copyright file. + * Removing now useless lintian override. + * Removing now useless manpage. + * Removing now useless patches. + * Removing now useless docs. + * Updating rules to for new upstream. + + -- Daniel Baumann Sun, 28 Sep 2008 11:56:00 +0200 + +dosfstools (2.11-8) unstable; urgency=low + + * Adding debug package. + + -- Daniel Baumann Sat, 20 Sep 2008 21:52:00 +0200 + +dosfstools (2.11-7) unstable; urgency=low + + * Adding manpage for dosfslabel, thanks to Francois Wendling + (Closes: #496760). + * Updating vcs fields in control file. + * Using patch-stamp rather than patch in rules file. + + -- Daniel Baumann Sat, 20 Sep 2008 21:48:00 +0200 + +dosfstools (2.11-6) unstable; urgency=high + + * Temporarily disabling bootcode.dpatch since it breaks syslinux, + thanks to Joey Hess (Closes: #489292). + + -- Daniel Baumann Fri, 4 Jul 2008 20:28:00 +0200 + +dosfstools (2.11-5) unstable; urgency=medium + + * Adding patch to mention fsckNNNN.rec files in dosfsck manpage + (Closes: #444596). + * Adding patch from Sam Bingner to add option for using a + bootcode template (Closes: #303442). + * Adding patch from Adonikam Virgo to fix backup + sector getopt (Closes: #232387, #479794). + * Adding patch from Karl Tomlinson to fix segfaults with + zero slots in lfn (Closes: #152550, #353198, #356377, #401798). + * Rediffing 99-conglomeration.dpatch. + * Adding patch from Eero Tamminen to improve memory + efficiencey when checking filesystems. + * Adding patch to list alternative binary names in manpage synopsis + (Closes: #284983). + * Adding patch to not deny FAT32 auto-selection in mkdosfs manpage + (Closes: #414183). + * Adding patch to not use confusing 'drop' in dosfsck manpage where 'delete' + in dosfsck manpage where 'delete' is meant (Closes: #134100). + * Listing alternative binary names in long-description (Closes: #434381). + * Updating manpage spelling patch to also cover wrong acknowledge header + (Closes: #306659). + * Breaking out manpage typos patch. + + -- Daniel Baumann Fri, 27 Jun 2008 09:03:00 +0200 + +dosfstools (2.11-4) unstable; urgency=low + + * Redone debian packaging from scratch. + * Both stop avoiding -O2 and stop adding -fno-strict-aliasing to OPTFLAGS on + alpha; seems not to be required anymore. + * Added patch from Jakub Jelinek to support + -D_FORTIFY_SOURCE=2 (for future use). + * Added patch from Jeremy Katz to add dosfslabel + (originally by Peter Jones). + * Added patch from Pavol Rusnak to use O_EXCL in mkdosfs. + * Added patch from Petr Gajdos to automatically determine + sector size of the device. + + -- Daniel Baumann Thu, 26 Jun 2008 13:13:00 +0200 + +dosfstools (2.11-3) unstable; urgency=low + + * New maintainer (Closes: #488018). + + -- Daniel Baumann Thu, 26 Jun 2008 12:31:00 +0200 + +dosfstools (2.11-2.3) unstable; urgency=low + + * NMU + * dpkg --print-gnu-build-architecture is gone, use dpkg-architecture + instead. Closes: #407192 + * Fixed errors in the mkdosfs manpage that could cause confusion to + readers, Thanks to Onno Benschop. Closes: #433561 (LP: #126121) + + -- Joey Hess Mon, 10 Sep 2007 15:57:36 -0400 + +dosfstools (2.11-2.2) unstable; urgency=low + + * Non-maintainer upload. + * Apply Ubuntu patches. Closes: #417673 + + -- Andreas Barth Sat, 9 Jun 2007 21:18:21 +0000 + +dosfstools (2.11-2.1) unstable; urgency=low + + * Non-maintainer upload. + * Fix unaligned memory accesses which cause warnings to appear everytime + the elilo bootloader script runs. This has led a number of users to + believe their install has failed. Thanks to Khalid Aziz for the patch. + Closes: #258839. + + -- dann frazier Thu, 9 Jun 2005 18:14:45 -0600 + +dosfstools (2.11-2) unstable; urgency=low + + * Oops, debian/rules overrides OPTFLAGS and therefore the + -D_FILE_OFFSET_BITS=64 in the toplevel Makefile had no effect; added + $(shell getconf LFS_CFLAGS) to OPTFLAGS as suggested by Lars Wirzenius in + #300126. Sorry, I tested a version compiled by the upstream Makefile... + Closes: #300126, #301254. + * #302517 was indeed the same as #294177, and fix is the same (use __u8) as + in 2.11-1. Closes: #302517. + + -- Roman Hodek Sun, 3 Apr 2005 13:56:55 +0200 + +dosfstools (2.11-1) unstable; urgency=low + + * New upstream version (Closes: #293394, #295181, #294177, #270023, #258402, + #232482, #214656, #286219, #276834, #266254, #128800) + + -- Roman Hodek Sat, 12 Mar 2005 17:19:27 +0100 + +dosfstools (2.10-1) unstable; urgency=low + + * New upstream version: + - dosfsck: various 64-bit fixes and removed some warnings by Michal + Cihar + - mkdosfs: better error message if called without parameters (also + suggested by Michal) + * recompilation removed errno@GLIBC_2.0 symbol; Closes: #168540 + (probably already 2.9-1 did) + + -- Roman Hodek Mon, 22 Sep 2003 22:15:32 +0200 + +dosfstools (2.9-1) unstable; urgency=low + + * New upstream version: + (Closes: #156266, #139198, #152769, #152868, #181196) + - dosfsck: if EOF from stdin, exit with error code + - dosfsck: Fix potential for "Internal error: next_cluster on bad cluster". + - dosfsck: When clearing long file names, don't overwrite the dir + entries with all zeros, but put 0xe5 into the first byte. + Otherwise, some OSes stop reading the directory at that point... + - dosfsck: in statistics printed by -v, fix 32bit overflow in number + of data bytes. + - dosfsck: fix an potential overflow in "too many clusters" check + - dosfsck: fix 64bit problem in fat.c (Debian bug #152769) + - dosfsck: allow FAT size > 32MB. + - dosfsck: allow for only one FAT + - dosfsck: with -v, also check that last sector of the filesystem can + be read (in case a partition is smaller than the fs thinks) + - mkdosfs: add note in manpage that creating bootable filesystems is + not supported. + - mkdosfs: better error message with pointer to -I if target is a + full-disk device. + * debian/control: Added build dependency on debhelper (Closes: #168388) + * debian/control: spelling fix (Closes: #124564) + * debian/control: metion names of tools in description (Closes: #186047) + + -- Roman Hodek Thu, 15 May 2003 20:54:04 +0200 + +dosfstools (2.8-1) unstable; urgency=low + + * New upstream version fixing an endless loop. + (Closes: #87205, #86373, #87590) + + -- Roman Hodek Wed, 28 Feb 2001 17:23:16 +0100 + +dosfstools (2.7-1) unstable; urgency=low + + * New upstream version with various bug fixes. (Closes: #83883) + * Changed maintainer e-mail addr. + + -- Roman Hodek Wed, 14 Feb 2001 12:49:00 +0100 + +dosfstools (2.6-1) unstable; urgency=low + + * New upstream version with various bug fixes. + + -- Roman Hodek Tue, 28 Nov 2000 17:27:35 +0100 + +dosfstools (2.5-1) unstable; urgency=low + + * New upstream version fixing llseek() on alpha (Closes: #54145) + + -- Roman Hodek Fri, 7 Jan 2000 09:26:51 +0100 + +dosfstools (2.4-1) unstable; urgency=low + + * New upstream version fixing compilation problem on alpha (Closes: #48331) + + -- Roman Hodek Tue, 26 Oct 1999 09:38:39 +0200 + +dosfstools (2.3-1) unstable; urgency=low + + * New upstream version: + - Manpage fixes. + - Fixed usage message of mkdosfs. + - Fixed compilation on alpha (llseek). + - Fixed unaligned accesses on alpha (Closes: #47714) + - Fixed renaming of files in dosfsck (extension wasn't really + written). Closes: #45774 + * Remove bashisms from debian/rules. + * FHS transition. + * On alpha, omit -O2 and add -fno-strict-aliasing to OPTFLAGS, as + otherwise the programs fail with unaligned traps. + * FHS transition (Standards-Version 3.0.1). + + -- Roman Hodek Fri, 22 Oct 1999 13:30:59 +0200 + +dosfstools (2.2-1) unstable; urgency=low + + * New upstream version. Closes: #40533 + * Updated copyright file for new location /usr/share/common-licenses/GPL. + * Updated Standards-Version to 3.0.0. + + -- Roman Hodek Tue, 6 Jul 1999 16:07:22 +0200 + +dosfstools (2.1-1) unstable; urgency=low + + * New upstream version. + * Also installs symlinks mkfs.vfat and fsck.vfat,so that also + filesystems listed with type "vfat" in /etc/fstab can be automatically + checked. + + -- Roman Hodek Fri, 28 May 1999 11:25:17 +0200 + +dosfstools (2.0-1) unstable; urgency=low + + * I'm now upstream maintainer, too. + * Adapted debian/rules for new central Makefile and rewritten to + debhelper. + * Fixed harmless warnings in mkdosfs.c and fat.c. + * mkdosfs.c: Return type of getopt() must be stored in an int, not in a + char. (Showed up on powerpc, where chars are default unsigned.) + + -- Roman Hodek Fri, 30 Apr 1999 14:37:37 +0200 + +dosfstools (1.0-16) unstable; urgency=low + + * Both tools are not maintained upstreams anymore, so I take over + general maintainership now... + * Both mkdosfs and dosfsck now support the FAT32 format. dosfsck + automatically detects it. For mkdosfs, 32 is now a valid argument to + -F, but FAT32 format isn't selected automatically (yet). With FAT32, + you can also set the number of reserved sectors (-R) and location of + the boot sector backup (-b) if you like (defaults are reasonable). + * dosfsck can handle and check VFAT-style long filenames now. It uses + the long names in listing etc. when available. There are also some + checks on the structures of LFNs and some fixes for possible problems. + * Implemented Atari format in both, dosfsck and mkdosfs. Under Atari TOS + basically the same FAT format is used as under DOS, however, there are + some little differences. Both tools now automatically select Atari + format if they run on an Atari. You can switch between standard MS-DOS + and Atari format with the -A option. + * Applied patch by Giuliano Procida to add loop + device support to mkdosfs: Usual floppy sizes are detected and + parameters (media byte,...) are set up accordingly. + My own additions to this: Don't die on loop devices that don't have + such a floppy size, but use some default hd params. Added endianess + conversions to Giulianos patch. + * More/better data in boot sector dump of dosfsck -v. + * Fixed lots of gcc warnings in the source. Removed -Wno-parentheses flag. + * Made dosfsck -v a bit more verbose. + * Extended README's for FAT32/LFN. + * Written a README for Atari format differences. + * Some minor cleanups in debian/rules. + * Install README files as README.{mkdosfs,dosfsck,Atari}.gz. + * AFAIK the tools still have alignment problems on Alpha machines. + Someone wanted to send me a patch, but I haven't heard from him for + months... + * Set Standards-Version to 2.5.0.0 (no changes). + + -- Roman Hodek Wed, 28 Apr 1999 11:06:15 +0200 + +dosfstools (1.0-15) frozen unstable; urgency=low + + * Applied patch by Juan Cespedes to make mkdosfs + work with newer 2.1 kernels again. (Fixes: #20320) + * Remove CC=gcc in debian/rules to make cross-compiling possible. + + -- Roman Hodek Thu, 30 Apr 1998 17:09:08 +0200 + +dosfstools (1.0-14) frozen unstable; urgency=medium + + * New maintainer + * Ignore long name directory slots of VFAT, instead of trying to correct + that "file names". Fixes: #20711 + * Don't consider file names with chars >= 128 to be bad, they're allowed. + + -- Roman Hodek Thu, 30 Apr 1998 10:00:16 +0200 + +dosfstools (1.0-13) stable; urgency=low + + * Fixed nasty bug that caused every file with a name like xxxxxxxx.xxx + to be treated as bad name that needed to be fixed. (closes: Bug#17389) + + -- Martin Schulze Thu, 26 Feb 1998 01:14:40 +0100 + +dosfstools (1.0-12) stable; urgency=low + + * Moved executables and their links into /sbin (Bug#15037) + * Corrected Standards-Version to 2.3.0.1 + + -- Martin Schulze Fri, 9 Jan 1998 21:49:48 +0100 + +dosfstools (1.0-11) stable; urgency=low + + * Applied patches to source files from Juan Cespedes which got lost in + the last upload (Bug#16493, Bug#16494, Bug#16490) + * build-stamp is now removed first in clean target (Bug#16491) + + -- Martin Schulze Sat, 3 Jan 1998 15:06:27 +0100 + +dosfstools (1.0-10) stable; urgency=low + + * Added links for mkfs.msdos and fsck.msdos (Bug#15037) + * Added links for mkfs.msdos.8 and fsck.msdos.8 + * Corrected source location + * Rewrote bad_name() (Bug#9871, part 2) + * s/int/time_t in check.c to omit a compiler warning (Bug#9871, part 3.1) + * Modified defaults, interactive is the default now + * Fixed renaming of files, they are saved now (Bug#9871, part 1) + * Fixed return type of date_dos2unix (Bug#9871, part 3.2) + + -- Martin Schulze Wed, 31 Dec 1997 18:59:53 +0100 + +dosfstools (1.0-9.1) unstable; urgency=low + + * Non-maintainer release + * .diff file was wrong in 1.0-9; fixed (Bug#13102) + * Fixed endianess patches (fixes Bug#11648) + * Built with libc6 + + -- Juan Cespedes Thu, 23 Oct 1997 23:19:34 +0200 + +dosfstools (1.0-9) stable; urgency=low + + * Added endianess patches from Frank Neumann + (Bug#9959) + * Updated Werner Almesbergers address + * Added -I switch to mkdosfs to allow full disk devices (Bug#10789) + + -- Martin Schulze Sun, 20 Jul 1997 14:51:33 +0200 + +dosfstools (1.0-8) stable; urgency=low + + * Fixed typo in mkdosfs.c (Bug#7396) + + * New maintainer address + + -- Martin Schulze Mon, 28 Apr 1997 12:51:13 +0200 + +dosfstools (1.0-7) stable; urgency=low + + * Minor fixes + + * Converted to Standards-Version 2.1.1.2 + + -- Martin Schulze Sat, 8 Feb 1997 15:03:52 +0100 + +Mon Jan 20 22:45:23 1997 Martin Schulze + + * debian.control: Corrected otherfs to otherosfs :-) + +Sun Jan 19 23:57:09 1997 Martin Schulze + + * mkdosfs.c: Removed one line printing out debug information. + +Wed Jan 15 00:25:02 1997 Martin Schulze + + * mkdosfs.c: Modified code to work properly under AXP. Thanks to + Matt Gundry for contacting me and + providing patched sources. + +Mon Jan 13 13:00:14 1997 Martin Schulze + + * mkdosfs.c: Added patch from Sven Rudolph + to support creation on disk images as well. + +Tue Jan 7 12:04:21 1997 Martin Schulze + + * Moved into section 'otherfs' + +-- Released 1.0-4 + +Sun Dec 22 11:28:03 1996 Martin Schulze + + * debian.rules: Installed ChangeLog + +Wed Aug 7 19:07:15 1996 Martin Schulze + + * Corrected debian.rules to provide $(package)_$(revision).diff.gz + +Mon Aug 5 11:13:34 1996 Martin Schulze + + * Added Conflicts: and Provides: entries in control file to really + replace mkdosfs. Thanks to Michael Meskes for reporting this bug. + +Thu Jul 18 22:01:34 1996 Martin Schulze + + * added dosfscheck to the package + +Wed Jul 3 00:57:23 1996 Martin Schulze + + * Added debian specific files + + * mkdosfs.c: inserted some brackets to stop gcc from moaning + + * mkdosfs.8: corrected some bold/inverse text phrases + + * mkdosfs.c: initialized a variable to stop gcc from moaning diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +7 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..0c19ad0 --- /dev/null +++ b/debian/control @@ -0,0 +1,35 @@ +Source: dosfstools +Section: otherosfs +Priority: optional +Maintainer: Daniel Baumann +Build-Depends: debhelper (>= 7) +Standards-Version: 3.8.0 +Homepage: http://www.daniel-baumann.ch/software/dosfstools/ +Vcs-Browser: http://git.debian.net/?p=debian/dosfstools.git +Vcs-Git: git://git.debian.net/git/debian/dosfstools.git + +Package: dosfstools +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: utilities for making and checking MS-DOS FAT filesystems + The dosfstools package includes the mkdosfs (aka mkfs.dos and mkfs.vfat) and + dosfsck (aka fsck.msdos and fsck.vfat) utilities, which respectively make and + check MS-DOS FAT filesystems on hard drives or on floppies. + . + This version uses the enhanced boot sector/superblock format of DOS 3.3+ as + well as provides a default dummy boot sector code. + +Package: dosfstools-dbg +Section: devel +Priority: extra +Architecture: any +Depends: dosfstools (= ${binary:Version}) +Description: utilities for making and checking MS-DOS FAT filesystems (debug) + The dosfstools package includes the mkdosfs (aka mkfs.dos and mkfs.vfat) and + dosfsck (aka fsck.msdos and fsck.vfat) utilities, which respectively make and + check MS-DOS FAT filesystems on hard drives or on floppies. + . + This version uses the enhanced boot sector/superblock format of DOS 3.3+ as + well as provides a default dummy boot sector code. + . + This package contains the debugging symbols. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..ad967ff --- /dev/null +++ b/debian/copyright @@ -0,0 +1,88 @@ +Author: Daniel Baumann +Download: http://www.daniel-baumann.ch/software/dosfstools/ + +Files: * +Copyright: (C) 1999-2005 Roman Hodek +License: GPL-2+ + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + . + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-2 file. + +Files: dosfsck/* +Copyright: + (C) 1999-2005 Werner Almesberger + (C) 1999-2005 Roman Hodek +License: GPL-2+ + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + . + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-2 file. + +Files: mkdosfs/* +Copyright: + (C) 1993-1994 David Hudson + (C) 1991 Linus Torvalds + (C) 1992-1993 Remy Card + (C) 1999-2005 Roman Hodek +License: GPL-2+ + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + . + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-2 file. + +Files: debian/* +Copyright: (C) 2008 Daniel Baumann +License: GPL-2+ + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + . + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-2 file. diff --git a/debian/doc/HISTORY b/debian/doc/HISTORY new file mode 100644 index 0000000..1b769bd --- /dev/null +++ b/debian/doc/HISTORY @@ -0,0 +1,20 @@ +This package was put together by Martin Schulze , from +sources obtained from: + sunsite.unc.edu:/pub/Linux/system/filesystems/dosfs/mkdosfs-ygg-0.3b.lsm + sunsite.unc.edu:/pub/Linux/system/filesystems/dosfs/mkdosfs-ygg-0.3b.tar.gz + sunsite.unc.edu:/pub/Linux/system/filesystems/dosfs/dosfsck.1.tar.z + +Mkdosfs is copyrighted by Dave Hudson , and was later +maintained and improved by H. Peter Anvin . Dave has put the +whole package under the GPL. + +Dosfsck is copyrighted by Werner Almesberger +and Roman Hodek. We both together put the package under the GPL. + +The FAT32, LFN, and Atari format additions are copyrighted by Roman Hodek + and are under the GPL, too. + +Both tools (mkdosfs and dosfsck) have been unmaintained since some time, so I +also took them over as upstream maintainer. The merged package is named +dosfstools-2.0, and its home site is now + ftp.uni-erlangen.de:/pub/Linux/LOCAL/dosfstools diff --git a/debian/docs b/debian/docs new file mode 100644 index 0000000..5ec07b2 --- /dev/null +++ b/debian/docs @@ -0,0 +1 @@ +debian/doc/* diff --git a/debian/patches/14-bootcode.dpatch b/debian/patches/14-bootcode.dpatch new file mode 100644 index 0000000..2d58349 --- /dev/null +++ b/debian/patches/14-bootcode.dpatch @@ -0,0 +1,235 @@ +#!/bin/sh /usr/share/dpatch/dpatch-run +## 14-bootcode.dpatch by Sam Bingner +## +## DP: Adds option for using a bootcode template (Closes: #303442). + +@DPATCH@ + +diff -Naurp dosfstools.orig/mkdosfs/ChangeLog dosfstools/mkdosfs/ChangeLog +--- dosfstools.orig/mkdosfs/ChangeLog 2008-06-27 05:37:31.000000000 +0000 ++++ dosfstools/mkdosfs/ChangeLog 2008-06-27 06:44:05.000000000 +0000 +@@ -1,3 +1,14 @@ ++19th June 2003 Sam Bingner (sam@bingner.com) ++ ++ Added option to read in bootcode from a file so that if you have ++ for example Windows 2000 boot code, you can have it write that ++ as the bootcode. This is a dump of the behinning of a partition ++ generally 512 bytes, but can be up to reserved sectors*512 bytes. ++ Also writes 0x80 as the BIOS drive number if we are formatting a ++ hard drive, and sets the number of hidden sectors to be the ++ number of sectors in one track. These were required so that DOS ++ could boot using the bootcode. ++ + 28th January 1995 H. Peter Anvin (hpa@yggdrasil.com) + + Better algorithm to select cluster sizes on large filesystems. +diff -Naurp dosfstools.orig/mkdosfs/mkdosfs.8 dosfstools/mkdosfs/mkdosfs.8 +--- dosfstools.orig/mkdosfs/mkdosfs.8 2008-06-27 06:34:35.000000000 +0000 ++++ dosfstools/mkdosfs/mkdosfs.8 2008-06-27 06:44:05.000000000 +0000 +@@ -44,6 +44,10 @@ + .I message-file + ] + [ ++.B \-B ++.I bootcode-file ++] ++[ + .B \-n + .I volume-name + ] +@@ -163,6 +167,18 @@ file must not exceed 418 bytes once line + carriage return-line feed combinations, and tabs have been expanded. + If the filename is a hyphen (-), the text is taken from standard input. + .TP ++.BI \-B " bootcode-file" ++Uses boot machine code from file "file". On any thing other than FAT32, ++this only writes the first 3 bytes, and 480 bytes from offset 3Eh. On ++FAT32, this writes the first 3 bytes, 420 bytes from offset 5Ah to both ++primary and backup boot sectors. Also writes all other reserved sectors ++excluding the sectors following boot sectors (usually sector 2 and 7). ++Does not require that the input file be as large as reserved_sectors*512. ++To make a FAT32 partition bootable, you will need at least the first ++13 sectors (6656 bytes). You can also specify a partition as the argument ++to clone the boot code from that partition. ++i.e mkdosfs -B /dev/sda1 /dev/sda1 ++.TP + .BI \-n " volume-name" + Sets the volume name (label) of the file system. The volume name can + be up to 11 characters long. The default is no label. +diff -Naurp dosfstools.orig/mkdosfs/mkdosfs.c dosfstools/mkdosfs/mkdosfs.c +--- dosfstools.orig/mkdosfs/mkdosfs.c 2008-06-27 06:34:35.000000000 +0000 ++++ dosfstools/mkdosfs/mkdosfs.c 2008-06-27 06:50:19.000000000 +0000 +@@ -24,6 +24,12 @@ + - New options -A, -S, -C + - Support for filesystems > 2GB + - FAT32 support ++ ++ Fixes/additions June 2003 by Sam Bingner ++ : ++ - Add -B option to read in bootcode from a file ++ - Write BIOS drive number so that FS can properly boot ++ - Set number of hidden sectors before boot code to be one track + + Copying: Copyright 1993, 1994 David Hudson (dave@humbug.demon.co.uk) + +@@ -153,6 +159,8 @@ cdiv (int a, int b) + #define FAT_BAD 0x0ffffff7 + + #define MSDOS_EXT_SIGN 0x29 /* extended boot sector signature */ ++#define HD_DRIVE_NUMBER 0x80 /* Boot off first hard drive */ ++#define FD_DRIVE_NUMBER 0x00 /* Boot off first floppy drive */ + #define MSDOS_FAT12_SIGN "FAT12 " /* FAT12 filesystem signature */ + #define MSDOS_FAT16_SIGN "FAT16 " /* FAT16 filesystem signature */ + #define MSDOS_FAT32_SIGN "FAT32 " /* FAT32 filesystem signature */ +@@ -175,6 +183,8 @@ cdiv (int a, int b) + #define BOOTCODE_SIZE 448 + #define BOOTCODE_FAT32_SIZE 420 + ++#define MAX_RESERVED 0xFFFF ++ + /* __attribute__ ((packed)) is used on all structures to make gcc ignore any + * alignments */ + +@@ -202,7 +212,7 @@ struct msdos_boot_sector + __u16 fat_length; /* sectors/FAT */ + __u16 secs_track; /* sectors per track */ + __u16 heads; /* number of heads */ +- __u32 hidden; /* hidden sectors (unused) */ ++ __u32 hidden; /* hidden sectors (one track) */ + __u32 total_sect; /* number of sectors (if sectors == 0) */ + union { + struct { +@@ -285,6 +295,8 @@ char dummy_boot_code[BOOTCODE_SIZE] = + + /* Global variables - the root of all evil :-) - see these and weep! */ + ++static char *template_boot_code; /* Variable to store a full template boot sector in */ ++static int use_template = 0; + static char *program_name = "mkdosfs"; /* Name of the program */ + static char *device_name = NULL; /* Name of the device on which to create the filesystem */ + static int atari_format = 0; /* Use Atari variation of MS-DOS FS format */ +@@ -837,6 +849,12 @@ setup_tables (void) + vi->volume_id[2] = (unsigned char) ((volume_id & 0x00ff0000) >> 16); + vi->volume_id[3] = (unsigned char) (volume_id >> 24); + } ++ if (bs.media == 0xf8) { ++ vi->drive_number = HD_DRIVE_NUMBER; /* Set bios drive number to 80h */ ++ } ++ else { ++ vi->drive_number = FD_DRIVE_NUMBER; /* Set bios drive number to 00h */ ++ } + + if (!atari_format) { + memcpy(vi->volume_label, volume_name, 11); +@@ -881,7 +899,7 @@ setup_tables (void) + printf( "Using %d reserved sectors\n", reserved_sectors ); + bs.fats = (char) nr_fats; + if (!atari_format || size_fat == 32) +- bs.hidden = CT_LE_L(hidden_sectors); ++ bs.hidden = bs.secs_track; + else { + /* In Atari format, hidden is a 16 bit field */ + __u16 hidden = CT_LE_W(hidden_sectors); +@@ -1362,6 +1380,32 @@ write_tables (void) + * dir area on FAT12/16, and the first cluster on FAT32. */ + writebuf( (char *) root_dir, size_root_dir, "root directory" ); + ++ if (use_template == 1) { ++ /* dupe template into reserved sectors */ ++ seekto( 0, "Start of partition" ); ++ if (size_fat == 32) { ++ writebuf( template_boot_code, 3, "backup jmpBoot" ); ++ seekto( 0x5a, "sector 1 boot area" ); ++ writebuf( template_boot_code+0x5a, 420, "sector 1 boot area" ); ++ seekto( 512*2, "third sector" ); ++ if (backup_boot != 0) { ++ writebuf( template_boot_code+512*2, backup_boot*sector_size - 512*2, "data to backup boot" ); ++ seekto( backup_boot*sector_size, "backup boot sector" ); ++ writebuf( template_boot_code, 3, "backup jmpBoot" ); ++ seekto( backup_boot*sector_size+0x5a, "backup boot sector boot area" ); ++ writebuf( template_boot_code+0x5a, 420, "backup boot sector boot area" ); ++ seekto( (backup_boot+2)*sector_size, "sector following backup code" ); ++ writebuf( template_boot_code+(backup_boot+2)*sector_size, (reserved_sectors-backup_boot-2)*512, "remaining data" ); ++ } else { ++ writebuf( template_boot_code+512*2, (reserved_sectors-2)*512, "remaining data" ); ++ } ++ } else { ++ writebuf( template_boot_code, 3, "jmpBoot" ); ++ seekto( 0x3e, "sector 1 boot area" ); ++ writebuf( template_boot_code+0x3e, 448, "boot code" ); ++ } ++ } ++ + if (blank_sector) free( blank_sector ); + if (info_sector) free( info_sector ); + free (root_dir); /* Free up the root directory space from setup_tables */ +@@ -1376,7 +1420,7 @@ usage (void) + { + fatal_error("\ + Usage: mkdosfs [-A] [-c] [-C] [-v] [-I] [-l bad-block-file] [-b backup-boot-sector]\n\ +- [-m boot-msg-file] [-n volume-name] [-i volume-id]\n\ ++ [-m boot-msg-file] [-n volume-name] [-i volume-id] [-B bootcode]\n\ + [-s sectors-per-cluster] [-S logical-sector-size] [-f number-of-FATs]\n\ + [-h hidden-sectors] [-F fat-size] [-r root-dir-entries] [-R reserved-sectors]\n\ + /dev/name [blocks]\n"); +@@ -1440,7 +1484,7 @@ main (int argc, char **argv) + printf ("%s " VERSION " (" VERSION_DATE ")\n", + program_name); + +- while ((c = getopt (argc, argv, "Ab:cCf:F:Ii:l:m:n:r:R:s:S:h:v")) != EOF) ++ while ((c = getopt (argc, argv, "AB:b:cCf:F:Ii:l:m:n:r:R:s:S:h:v")) != EOF) + /* Scan the command line for options */ + switch (c) + { +@@ -1510,6 +1554,51 @@ main (int argc, char **argv) + listfile = optarg; + break; + ++ case 'B': /* B : read in bootcode */ ++ if ( strcmp(optarg, "-") ) ++ { ++ msgfile = fopen(optarg, "r"); ++ if ( !msgfile ) ++ perror(optarg); ++ } ++ else ++ msgfile = stdin; ++ ++ if ( msgfile ) ++ { ++ if (!(template_boot_code = malloc( MAX_RESERVED ))) ++ die( "Out of memory" ); ++ /* The template boot sector including reserved must not be > 65535 */ ++ use_template = 1; ++ i = 0; ++ do ++ { ++ ch = getc(msgfile); ++ switch (ch) ++ { ++ case EOF: ++ break; ++ ++ default: ++ template_boot_code[i++] = ch; /* Store character */ ++ break; ++ } ++ } ++ while ( ch != EOF && i < MAX_RESERVED ); ++ ch = getc(msgfile); /* find out if we're at EOF */ ++ ++ /* Fill up with zeros */ ++ while( i < MAX_RESERVED ) ++ template_boot_code[i++] = '\0'; ++ ++ if ( ch != EOF ) ++ printf ("Warning: template too long; truncated after %d bytes\n", i); ++ ++ if ( msgfile != stdin ) ++ fclose(msgfile); ++ } ++ break; ++ + case 'm': /* m : Set boot message */ + if ( strcmp(optarg, "-") ) + { diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..f1c4e7d --- /dev/null +++ b/debian/rules @@ -0,0 +1,46 @@ +#!/usr/bin/make -f + +clean: + dh_testdir + dh_testroot + rm -f build-stamp + + $(MAKE) distclean + + dh_clean + +build: build-stamp +build-stamp: + dh_testdir + + $(MAKE) + + touch build-stamp + +install: build + dh_testdir + dh_testroot + dh_prep + dh_installdirs + + $(MAKE) DESTDIR=$(CURDIR)/debian/dosfstools PREFIX=/usr SBINDIR=/sbin install + +binary: binary-arch + +binary-arch: build install + dh_testdir + dh_testroot + dh_installchangelogs ChangeLog + dh_installdocs + dh_strip --dbg-package=dosfstools-dbg + dh_compress + dh_fixperms + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary-indep: + +.PHONY: clean build install binary binary-arch binary-indep diff --git a/doc/ANNOUNCE.mkdosfs b/doc/ANNOUNCE.mkdosfs new file mode 100644 index 0000000..1f02ea2 --- /dev/null +++ b/doc/ANNOUNCE.mkdosfs @@ -0,0 +1,41 @@ +Announcing the release of mkdosfs version 0.3b (Yggdrasil) + +It seems I didn't get the bug completely fixed in 0.3a. Some +borderline cases would still allocate too many sectors for the FAT. +Again, nothing to worry about, just a nitpick -- this one would only +in certain cases add one sector per FAT. + +Announcing the release of mkdosfs version 0.3a (Yggdrasil) + +Fixed a bug which would cause too many sectors to be reserved for the +FAT (filesystem will still work fine, but have slightly less space +available). + +Announcing the release of mkdosfs version 0.3 (Yggdrasil) + +This version correctly handles even very large filesystems, and +properly supports the modern (3.3+) DOS bootsector format, including a +message printed on boot attempts. + +Peter Anvin +Yggdrasil Computing, Inc. +hpa@yggdrasil.com + + -------------- + +Announcing the release of mkdosfs version 0.2 + + +I've just uploaded mkdosfs to sunsite.unc.edu. It works in a similar way +to Remy Card's mke2fs, but creates an MS-DOS file system. + +The filename is mkdosfs-0.2.tar.gz. + +This second release should fix a small bug that could lead to FAT sizes that +Linux's dosfs would accept but MS-DOS wouldn't. + +The archive contains a manual page, binary and source versions. + + +Dave Hudson +dave@humbug.demon.co.uk diff --git a/doc/ChangeLog.dosfsck b/doc/ChangeLog.dosfsck new file mode 100644 index 0000000..f628ac2 --- /dev/null +++ b/doc/ChangeLog.dosfsck @@ -0,0 +1,10 @@ +Changes from version 0 to 1 +=========================== + + - fixed an off-by-two error in check.c:check_file + - fixed marking clusters bad in fat.c:set_fat + - fat.c:reclaim_free was also reclaiming bad clusters. + - fixed many incorrect byte sex conversions in check.c and fat.c + - -t and -w now require -a or -r + - added option -d to drop files. + - added option -u to try to "undelete" non-directory files. diff --git a/doc/ChangeLog.dosfstools-2.x b/doc/ChangeLog.dosfstools-2.x new file mode 100644 index 0000000..7ed9efe --- /dev/null +++ b/doc/ChangeLog.dosfstools-2.x @@ -0,0 +1,161 @@ +version 2.11 +============ + + - all: don't use own llseek() anymore, glibc lseek() does everything we need + - dosfsck: lfn.c: avoid segfault + - dosfsck: check.c, lfn.c: check for orphaned LFN slots + - dosfsck: check.c alloc_rootdir_entry(): set owner of newly alloced clusters + - dosfsck: dosfsck.h: better use for byte swapping + - dosfsck: io.c: added code for real DOS + - mkdosfs: raised FAT12_THRESHOLD from 4078 to 4085, introduced MIN_CLUST_32 + - mkdosfs: fix loop device size + - mkdosfs: by default, use FAT32 on devices >= 512MB + - mkdosfs: fix a memory leak (blank_sector) + - mkdosfs: fix parsing of number of blocks on command line, so that numbers + >2G can be used + - mkdosfs: add 'b' to getopt() string so this option can be used :) + - mkdosfs: fix parsing of -i arg (should be unsigned) + - mkdosfs: change default permissions of created images (-C) to 0666 & ~umask + - mkdosfs: relax geometry check: if HDIO_GETGEO fails, print a warning and + default to H=255,S=63 + - dosfsck: new option -n (no-op): just check non-interactively, but + don't write anything to filesystem + - A few #include changes to support compilation with linux 2.6 + headers (thanks to Jim Gifford ) + - dosfsck: remove directory entries pointing to start cluster 0, if they're + not "." or ".." entries that should actually point to the root dir + (pointed out by Thomas Winkler ) + - mkdosfs: new option -h to set number of hidden sectors + (thanks to Godwin Stewart ) + - all: updated my mail address everywhere... + +version 2.10 +============ + + - dosfsck: various 64-bit fixes and removed some warnings by Michal + Cihar + - mkdosfs: better error message if called without parameters (also + suggested by Michal) + +version 2.9 +=========== + + - dosfsck: if EOF from stdin, exit with error code + - dosfsck: Fix potential for "Internal error: next_cluster on bad cluster". + - dosfsck: When clearing long file names, don't overwrite the dir + entries with all zeros, but put 0xe5 into the first byte. + Otherwise, some OSes stop reading the directory at that point... + - dosfsck: in statistics printed by -v, fix 32bit overflow in number + of data bytes. + - dosfsck: fix an potential overflow in "too many clusters" check + - dosfsck: fix 64bit problem in fat.c (Debian bug #152769) + - dosfsck: allow FAT size > 32MB. + - dosfsck: allow for only one FAT + - dosfsck: with -v, also check that last sector of the filesystem can + be read (in case a partition is smaller than the fs thinks) + - mkdosfs: add note in manpage that creating bootable filesystems is + not supported. + - mkdosfs: better error message with pointer to -I if target is a + full-disk device. + +version 2.8 +=========== + + - dosfsck: Fixed endless loop whenever a volume label was present. + +version 2.7 +=========== + + - dosfsck: Don't check volume label for bad characters, everything + seems to be allowed there... Also ignore duplicate names where one of + them is a volume label. + +version 2.6 +=========== + + - mkdosfs: Added correct heads definition for 2.88M floppies if not + created via loopback. + - dosfsck: If boot sector and its backup are different (FAT32), offer + to write the backup to sector 0. (tnx to Pavel Roskin for this) + - For 64 bit alpha, struct bootsector in dosfsck.h must be defined + with __attribute__((packed)). + - mkdosfs now actually accepts -R option. (tnx to David Kerrawn) + - Fixed typo in dosfsck boot.c (recognition of boot signature in FSINFO) + - Various compilation fixes for 2.4 kernel headers and for ia64. + +version 2.5 +=========== + + - The llseek() implementation for alpha didn't really work; fixed it. + +version 2.4 +=========== + + - Fix compiling problem on alpha (made a silly typo...) + +version 2.3 +=========== + + - mkdosfs: Fixed usage message (printed only "bad address"). + - both: made man pages and usage statements more consistent. + - both: fix llseek function for alpha. + - dosfsck: fix reading of unaligned fields in boot sector for alpha. + - dosfsck: fixed renaming of files (extension wasn't really written). + +version 2.2 +=========== + + - Added dosfsck/COPYING, putting dosfsck officially under GPL (Werner + and I agree that it should be GPL). + - mkdosfs: Allow creation of a 16 bit FAT on filesystems that are too + small for it if the user explicitly selected FAT16 (but a warning + is printed). Formerly, you got the misleading error message "make + the fs a bit smaller". + - dosfsck: new option -y as synonym for -y; for compability with + other fs checkers, which also accept this option. + - dosfsck: Now prints messages similar to e2fsck: at start version + and feature list; at end number of files (and directories) and + number of used/total clusters. This makes the printouts of *fsck at + boot time nicer. + - dosfsck: -a (auto repair) now turns on -f (salvage files), too. -a + should act as non-destructive as possible, so lost clusters should + be assigned to files. Otherwise the data in them might be + overwritten later. + - dosfsck: Don't drop a directory with lots of bad entries in + auto-repair mode for the same reason as above. + - dosfsck: avoid deleting the whole FAT32 root dir if something is + wrong with it (bad start cluster or the like). + - general: also create symlinks {mkfs,fsck}.vfat.8 to the respective + real man pages. + +version 2.1 +=========== + + - Fix some forgotten loff_t's for filesystems > 4GB. (Thanks to + ). + - Fix typo in mkdosfs manpage. + - Removed inclusion of from mkdosfs.c; it's unnecessary and + caused problems in some environments. + - Fix condition when to expect . and .. entries in a directory. (Was + wrong for non-FAT32 if first entry in root dir was a directory also.) + - Also create mkfs.vfat and fsck.vfat symlinks, so that also + filesystems listed with type "vfat" in /etc/fstab can be + automatically checked. + +version 2.0 +=========== + + - merge of mkdosfs and dosfstools in one package + - new maintainer: Roman Hodek + - FAT32 support in both mkdosfs and dosfsck + - VFAT (long filename) support in dosfsck + - Support for Atari variant of MS-DOS filesystem in both tools + - Working support for big-endian systems in both tools + - Better support for loop devices in mkdosfs: usual floppy sizes are + detected and media byte etc. set accordingly; if loop fs has no + standard floppy size, use hd params + (mainly by Giuliano Procida ) + - Removed lots of gcc warnings + - Fixed some minor calculation bugs in mkdosfs. + +For change logs previous to 2.0, see the CHANGES files in the subdirectories. diff --git a/doc/ChangeLog.mkdosfs b/doc/ChangeLog.mkdosfs new file mode 100644 index 0000000..e39d9d6 --- /dev/null +++ b/doc/ChangeLog.mkdosfs @@ -0,0 +1,18 @@ +28th January 1995 H. Peter Anvin (hpa@yggdrasil.com) + + Better algorithm to select cluster sizes on large filesystems. + Added bogus boot sector code that on attempts to boot prints a + message (which can be chosen at mkdosfs time) and lets the user + press any key and try again. Corrected support for 1.2 Mb + floppies. mkdosfs now generates the extended bootsector + (superblock) format of DOS 3.3+, with support for volume ID's and + volume labels (volume labels are also written to the root + directory, as they should). + +18th February 1994 Dave Hudson (dave@humbug.demon.co.uk) + + Released version 0.2 - clears a bug in the FAT sizing code. + +1st September 1993 Dave Hudson (dave@humbug.demon.co.uk) + + Released version 0.1 - ALPHA release of mkdosfs diff --git a/doc/README.dosfsck b/doc/README.dosfsck new file mode 100644 index 0000000..7b351aa --- /dev/null +++ b/doc/README.dosfsck @@ -0,0 +1,60 @@ +dosfsck, version 1 +================== + +WARNING: This is ALPHA test software. Use at your own risk. + +dosfsck is the Linux equivalent of PC/MS-DOS' CHKDSK. It checks the +consistency of PC/MS-DOS file systems and optionally tries to repair +them. The tests dosfsck performs are described in the man page. + +dosfsck needs header files from dosfs.9 (or later) to compile. + +Before using dosfsck to repair a file system that contains data of any +value, you should verify that dosfsck is able to correct all reported +errors. (Except fatal errors and those reported as unfixable, of +course.) In order to do this, run it with the -V option, e.g. + + dosfsck -V /dev/sda1 (automatic check) +or dosfsck -V -r /dev/sda1 (interactive check and repair) + +dosfsck will perform two passes: in the first pass, inconsistencies are +detected and a list of changes to correct the problems is generated. In +the second pass, those changes are applied whenever dosfsck reads data +from disk. Hence no fixable errors should be reported in the second +pass if the first pass was successful. + +Please notify the author if fixable errors are reported in the second +pass. + +After verifying that dosfsck appears to be able to perform the desired +operations, either confirm that you want the changes to be performed +(if dosfsck was started with -r) or re-run dosfsck with the -a option +(if it was started without -r). + +Please send bug reports, comments, flames, etc. to +almesber@nessie.cs.id.ethz.ch or almesber@bernina.ethz.ch + +- Werner + +FAT32 and LFN support +===================== + +I've finally implemented some of the new features of MS-DOS +filesystems: FAT32 and long filenames. + +FAT32 is automatically detected and of course the different FAT +structure is handled. (Internally many changes were needed, so 32 bit +variables for all cluster numbers and 64 bit vars for offsets inside +the filesystem.) New checks for FAT32 are most notably on the backup +boot sector and the new info sector. Also the possibility that the +root directory resides in a cluster chain (instead of in a static +area) on FAT32 is handled. + +dosfscheck also knows about VFAT long filenames now. It parses those +names and uses them in listings etc. when available. There are also +some checks on the (cruel) structure of how LFNs are stored and some +attempts to fix problems. + +- Roman + +BTW, version 2 isn't ALPHA anymore :-) diff --git a/doc/README.dosfstools-2.x b/doc/README.dosfstools-2.x new file mode 100644 index 0000000..5fb00ed --- /dev/null +++ b/doc/README.dosfstools-2.x @@ -0,0 +1,60 @@ + +Atari format support +==================== + +Both mkdosfs and dosfsck now can also handle the Atari variation of +the MS-DOS filesystem format. The Atari format has some minor +differences, some caused by the different machine architecture (m68k), +some being "historic" (Atari didn't change some things that M$ +changed). + +Both tools automatically select Atari format if they run on an Atari. +Additionally the -A switch toggles between Atari and MS-DOS format. +I.e., on an Atari it selects plain DOS format, on any other machine it +switches to Atari format. + +The differences are in detail: + + - Atari TOS doesn't like cluster sizes != 2, so the usual solution + for bigger partitions was to increase the logical sector size. So + mkdosfs can handle sector sizes != 512 now, you can also manually + select it with the -S option. On filesystems larger than approx. 32 + MB, the sector size is automatically increased (stead of the + cluster size) to make the filesystem fit. mkdosfs will always use 2 + sectors per cluster (also with the floppy standard configurations), + except when directed otherwise on the command line. + + - From the docs, all values between 0xfff8 and 0xffff in the FAT mark + an end-of-file. However, DOS usually uses 0xfff8 and Atari 0xffff. + This seems to be only an consmetic difference. At least TOS doesn't + complain about 0xffff EOF marks. Don't know what DOS thinks of + 0xfff8 :-) Anyway, both tools use the EOF mark common to the + system (DOS/Atari). + + - Something similar of the bad cluster marks: On Atari the FAT values + 0xfff0 to 0xfff7 are used for this, under DOS only 0xfff7 (the + others can be normal cluster numbers, allowing 7 more clusters :-) + However, both systems usually mark with 0xfff7. Just dosfsck has to + interpret 0xfff0...0xfff7 differently. + + - Some fields in the boot sector are interpreted differently. For + example, Atari has a disk serial number (used to aid disk change + detection) where DOS stores the system name; the 'hidden' field is + 32 bit for DOS, but 16 bit for Atari, and there's no 'total_sect' + field; the 12/16 bit FAT decision is different: it's not based on + the number of clusters, but always FAT12 on floppies and FAT16 on + hard disks. mkdosfs nows about these differences and constructs the + boot sector accordingly. + + - In dosfsck, the boot sector differences also have to known, to not + warn about things that are no error on Atari. In addition, most + Atari formatting tools fill the 'tracks' and 'heads' fields with 0 + for hard disks, because they're meaningless on SCSI disks (Atari + has/had no IDE). Due to this, the check that they should be + non-zero is switched off. + + - Under Atari TOS, some other characters are illegal in filenames: + '<', '>', '|', '"', and ':' are allowed, but all non-ASCII chars + (codes >= 128) are forbidden. + +- Roman diff --git a/doc/README.mkdosfs b/doc/README.mkdosfs new file mode 100644 index 0000000..ae93ada --- /dev/null +++ b/doc/README.mkdosfs @@ -0,0 +1,50 @@ +mkdosfs - Make DOS file system utilty. + + +I wrote this, partially to complement the dosfsck utility written by Werner +Almesberger (who graciously gave me some pointers when I asked for some +advice about writing this code), and also to avoid me having to boot DOS +just to create data partitions (I use Linux to back up DOS :-) ). + +The code is really derived from Remy Card's mke2fs utility - I used this as a +framework, although all of the file system specific stuff was removed and the +DOS stuff inserted. I believe originally mke2fs was based on Linus' mkfs +code, hence the acknowledgements in the source code. + +Neither Remy nor Linus have had any involvement with mkdosfs, so if there are +any bugs they're almost certainly "all my own work". + +The code has been available for ftp since 1st September 1993, and I have yet +to receive any bug reports from users. I don't know of any bugs, but if you +do find a bug or have any constructive comments, please mail me! + +The only bug I found with version 0.1 was an obscure fault that could lead +to an invalid (for MS-DOS, not Linux's dos fs) number of sectors used in the +file allocation table(s). + + +Dave Hudson +dave@humbug.demon.co.uk + + +FAT32 support +============= + +mkdosfs now can also create filesystems in the new FAT32 format. To do +this, give mkdosfs a "-F 32" option. FAT32 isn't selected +automatically (yet), even if very large clusters are needed with +FAT16. With FAT32 you have two additional options, -R to select the +number of reserved sectors (usually 32), and -b to select the location +of the backup boot sector (default 6). Of course such a backup is +created, as well as the new info sector. On FAT32, the root directory +is always created as a cluster chain. Sorry, there's no switch to +generate an old static root dir. + +One bigger bug fix besides FAT32 was to reject filesystems that need a +16 bit FAT to fit all possible clusters, but the bigger FAT needs some +more sectors, so the total number of clusters drop below the border +where MS-DOS expects a 12 bit FAT. So such filesystems would be FAT16, +but interpreted as FAT32 by DOS. The fix is to reduce filesystem size +a bit. + +- Roman diff --git a/doc/TODO.dosfstools-2.x b/doc/TODO.dosfstools-2.x new file mode 100644 index 0000000..dbc2de0 --- /dev/null +++ b/doc/TODO.dosfstools-2.x @@ -0,0 +1,14 @@ + -*- mode: indented-text -*- + + - dosfsck: Better checking of file times: ctime <= mtime <= atime + + - mkdosfs: If /etc/bootsect.dos (or similar) exists, use it as a + template for generating boot sectors. This way, you can, e.g., make + bootable DOS disks. + + Addendum: Don't know if that's so wise... There are really many + variants of DOS/Windows bootcode out in the wild, and the code is + proprietary, too. + + - dosfsck: read-only sector test (-t without -a or -r); just print + out errors. diff --git a/man/dosfsck.8 b/man/dosfsck.8 new file mode 100644 index 0000000..9443543 --- /dev/null +++ b/man/dosfsck.8 @@ -0,0 +1,147 @@ +.TH DOSFSCK 8 "December 31 1997" "Linux" "MAINTENANCE COMMANDS" +.SH NAME +dosfsck \- check and repair MS-DOS file systems +.SH SYNOPSIS +.ad l +.B dosfsck|fsck.msdos|fsck.vfat +.RB [ \-aAflnrtvVwy ] +.RB [ \-d\ \fIpath\fB\ \-d\ \fI...\fB ] +.RB [ \-u\ \fIpath\fB\ \-u\ \fI...\fB ] +.I device +.ad b +.SH DESCRIPTION +.B dosfsck +verifies the consistency of MS-DOS file systems and optionally tries to +repair them. The following file system problems can be corrected (in this +order): +.IP \- +FAT contains invalid cluster numbers. Cluster is changed to EOF. +.PD 0 +.IP \- +File's cluster chain contains a loop. The loop is broken. +.IP \- +Bad clusters (read errors). The clusters are marked bad and they are +removed from files owning them. This check is optional. +.IP \- +Directories with a large number of bad entries (probably corrupt). The +directory can be deleted. +.IP \- +Files . and .. are non-directories. They can be deleted or renamed. +.IP \- +Directories . and .. in root directory. They are deleted. +.IP \- +Bad file names. They can be renamed. +.IP \- +Duplicate directory entries. They can be deleted or renamed. +.IP \- +Directories with non-zero size field. Size is set to zero. +.IP \- +Directory . does not point to parent directory. The start pointer is +adjusted. +.IP \- +Directory .. does not point to parent of parent directory. The start pointer +is adjusted. +.IP \- +Start cluster number of a file is invalid. The file is truncated. +.IP \- +File contains bad or free clusters. The file is truncated. +.IP \- +File's cluster chain is longer than indicated by the size fields. The file +is truncated. +.IP \- +Two or more files share the same cluster(s). All but one of the files are +truncated. If the file being truncated is a directory file that has already +been read, the file system check is restarted after truncation. +.IP \- +File's cluster chain is shorter than indicated by the size fields. The file +is truncated. +.IP \- +Clusters are marked as used but are not owned by a file. They are marked +as free. +.PD +.LP +Additionally, the following problems are detected, but not repaired: +.IP \- +Invalid parameters in boot sector. +.PD 0 +.IP \- +Absence of . and .. entries in non-root directories +.PD +.LP +When \fBdosfsck\fP checks a file system, it accumulates all changes in memory +and performs them only after all checks are complete. This can be disabled +with the \fB\-w\fP option. +.SH OPTIONS +.IP \fB\-a\fP +Automatically repair the file system. No user intervention is necessary. +Whenever there is more than one method to solve a problem, the least +destructive approach is used. +.IP \fB\-A\fP +Use Atari variation of the MS-DOS filesystem. This is default if +\fBdosfsck\fP is run on an Atari, then this option turns off Atari +format. There are some minor differences in Atari format: Some boot +sector fields are interpreted slightly different, and the special FAT +entries for end-of-file and bad cluster can be different. Under +MS-DOS 0xfff8 is used for EOF and Atari employs 0xffff by default, but +both systems recognize all values from 0xfff8...0xffff as end-of-file. +MS-DOS uses only 0xfff7 for bad clusters, where on Atari values +0xfff0...0xfff7 are for this purpose (but the standard value is still +0xfff7). +.IP \fB\-d\fP +Delete the specified file. If more that one file with that name exists, the +first one is deleted. +.IP \fB\-f\fP +Salvage unused cluster chains to files. By default, unused clusters are +added to the free disk space except in auto mode (\fB-a\fP). +.IP \fB\-l\fP +List path names of files being processed. +.IP \fB\-n\fP +No-operation mode: non-interactively check for errors, but don't write +anything to the filesystem. +.IP \fB\-r\fP +Interactively repair the file system. The user is asked for advice whenever +there is more than one approach to fix an inconsistency. +.IP \fB\-t\fP +Mark unreadable clusters as bad. +.IP \fB-u\fP +Try to undelete the specified file. \fBdosfsck\fP tries to allocate a chain +of contiguous unallocated clusters beginning with the start cluster of the +undeleted file. +.IP \fB\-v\fP +Verbose mode. Generates slightly more output. +.IP \fB\-V\fP +Perform a verification pass. The file system check is repeated after the +first run. The second pass should never report any fixable errors. It may +take considerably longer than the first pass, because the first pass may +have generated long list of modifications that have to be scanned for each +disk read. +.IP \fB\-w\fP +Write changes to disk immediately. +.IP \fB\-y\fP +Same as \fB\-a\fP (automatically repair filesystem) for compatibility +with other fsck tools. +.LP +If \fB\-a\fP and \fB\-r\fP are absent, the file system is only checked, +but not repaired. +.SH "EXIT STATUS" +.IP 0 +No recoverable errors have been detected. +.IP 1 +Recoverable errors have been detected or \fBdosfsck\fP has discovered an +internal inconsistency. +.IP 2 +Usage error. \fBdosfsck\fP did not access the file system. +.SH FILES +.IP "fsck0000.rec, fsck0001.rec, ..." +When recovering from a corrupted file system, dosfsck dumps recovered data +into files named 'fsckNNNN.rec' in the top level directory of the file system. +.SH BUGS +Does not create . and .. files where necessary. Does not remove entirely +empty directories. Should give more diagnostic messages. Undeleting files +should use a more sophisticated algorithm. +.\".SH "SEE ALSO" +.\"fs(5) +.SH AUTHORS +Werner Almesberger +Extensions (FAT32, VFAT) by and current maintainer: +Roman Hodek diff --git a/man/dosfslabel.8 b/man/dosfslabel.8 new file mode 100644 index 0000000..0dbc136 --- /dev/null +++ b/man/dosfslabel.8 @@ -0,0 +1,53 @@ +.TH "dosfslabel" "8" "13 August 2008" + +.SH "NAME" +dosfslabel \- set or get a MS-DOS filesystem label + +.SH "SYNOPSIS" +.PP +.B dosfslabel +.IR device \ [ label ] + + +.SH "DESCRIPTION" +.PP +This manual page documents briefly the +.B dosfslabel +command. +.PP +.B dosfslabel +set or gets a MS-DOS filesystem label from a given +.IR device . +If +.I label +is omitted, then the label name of the specified +.I device +is written on the standard output. + +.I label +can't be longer than 11 characters. + +.SH "OPTIONS" +.TP +.BR \-h , \-\-help +Displays a help message. +.TP +.BR \-V , \-\-version +Shows version. + +.SH "SEE ALSO" + +.BR mkfs.msdos (8), +.BR mkdosfs (8) + + +.SH "AUTHORS" +.PP +.B dosfslabel +is Copyright 2007 Red Hat, Inc. +.PP +Some portions are Copyright 1998 Roman Hodek. +.PP +Some portions are Copyright 1993 Werner Almesberger. + +This manual page was written by François Wendling for the Debian GNU/Linux system (but may be used by others). diff --git a/man/mkdosfs.8 b/man/mkdosfs.8 new file mode 100644 index 0000000..bb87ce6 --- /dev/null +++ b/man/mkdosfs.8 @@ -0,0 +1,211 @@ +.\" -*- nroff -*- +.TH MKDOSFS 8 "5 May 1995" "Version 2.x" +.SH NAME +.B mkdosfs +\- create an MS-DOS file system under Linux +.SH SYNOPSIS +.B mkdosfs|mkfs.msdos|mkfs.vfat +[ +.B \-A +] +[ +.B \-b +.I sector-of-backup +] +[ +.B \-c +] +[ +.B \-l +.I filename +] +[ +.B \-C +] +[ +.B \-f +.I number-of-FATs +] +[ +.B \-F +.I FAT-size +] +[ +.B \-h +.I number-of-hidden-sectors +] +[ +.B \-i +.I volume-id +] +.RB [ " \-I " ] +[ +.B \-m +.I message-file +] +[ +.B \-n +.I volume-name +] +[ +.B \-r +.I root-dir-entries +] +[ +.B \-R +.I number-of-reserved-sectors +] +[ +.B \-s +.I sectors-per-cluster +] +[ +.B \-S +.I logical-sector-size +] +[ +.B \-v +] +.I device +[ +.I block-count +] +.SH DESCRIPTION +.B mkdosfs +is used to create an MS-DOS file system under Linux on a device (usually +a disk partition). +.I device +is the special file corresponding to the device (e.g /dev/hdXX). +.I block-count +is the number of blocks on the device. If omitted, +.B mkdosfs +automatically determines the file system size. +.SH OPTIONS +.TP +.B \-A +Use Atari variation of the MS-DOS file system. This is default if +\fBmkdosfs\fP is run on an Atari, then this option turns off Atari +format. There are some differences when using Atari format: If not +directed otherwise by the user, \fBmkdosfs\fP will always use 2 +sectors per cluster, since GEMDOS doesn't like other values very much. +It will also obey the maximum number of sectors GEMDOS can handle. +Larger file systems are managed by raising the logical sector size. +Under Atari format, an Atari-compatible serial number for the +file system is generated, and a 12 bit FAT is used only for file systems +that have one of the usual floppy sizes (720k, 1.2M, 1.44M, 2.88M), a +16 bit FAT otherwise. This can be overridden with the \fB\-F\fP +option. Some PC-specific boot sector fields aren't written, and a boot +message (option \fB\-m\fP) is ignored. +.TP +.BI \-b " sector-of-backup " +Selects the location of the backup boot sector for FAT32. Default +depends on number of reserved sectors, but usually is sector 6. The +backup must be within the range of reserved sectors. +.TP +.B \-c +Check the device for bad blocks before creating the file system. +.TP +.B \-C +Create the file given as \fIdevice\fP on the command line, and write +the to-be-created file system to it. This can be used to create the +new file system in a file instead of on a real device, and to avoid +using \fBdd\fP in advance to create a file of appropriate size. With +this option, the \fIblock-count\fP must be given, because otherwise +the intended size of the file system wouldn't be known. The file +created is a sparse file, which actually only contains the meta-data +areas (boot sector, FATs, and root directory). The data portions won't +be stored on the disk, but the file nevertheless will have the +correct size. The resulting file can be copied later to a floppy disk +or other device, or mounted through a loop device. +.TP +.BI \-f " number-of-FATs" +Specify the number of file allocation tables in the file system. The +default is 2. Currently the Linux MS-DOS file system does not support +more than 2 FATs. +.TP +.BI \-F " FAT-size" +Specifies the type of file allocation tables used (12, 16 or 32 bit). +If nothing is specified, \fBmkdosfs\fR will automatically select +between 12, 16 and 32 bit, whatever fits better for the file system size. +.TP +.BI \-h " number-of-hidden-sectors " +Select the number of hidden sectors in the volume. Apparently some +digital cameras get indigestion if you feed them a CF card without +such hidden sectors, this option allows you to satisfy them. Assumes +\'0\' if no value is given on the command line. +.TP +.I \-i " volume-id" +Sets the volume ID of the newly created file system; +.I volume-id +is a 32-bit hexadecimal number (for example, 2e24ec82). The default +is a number which depends on the file system creation time. +.TP +.B \-I +It is typical for fixed disk devices to be partitioned so, by default, you are +not permitted to create a filesystem across the entire device. +.B mkdosfs +will complain and tell you that it refuses to work. This is different +when using MO disks. One doesn't always need partitions on MO disks. +The file system can go directly to the whole disk. Under other OSes +this is known as the 'superfloppy' format. + +This switch will force +.B mkdosfs +to work properly. +.TP +.BI \-l " filename" +Read the bad blocks list from +.IR filename . +.TP +.BI \-m " message-file" +Sets the message the user receives on attempts to boot this file system +without having properly installed an operating system. The message +file must not exceed 418 bytes once line feeds have been converted to +carriage return-line feed combinations, and tabs have been expanded. +If the filename is a hyphen (-), the text is taken from standard input. +.TP +.BI \-n " volume-name" +Sets the volume name (label) of the file system. The volume name can +be up to 11 characters long. The default is no label. +.TP +.BI \-r " root-dir-entries" +Select the number of entries available in the root directory. The +default is 112 or 224 for floppies and 512 for hard disks. +.TP +.BI \-R " number-of-reserved-sectors " +Select the number of reserved sectors. With FAT32 format at least 2 +reserved sectors are needed, the default is 32. Otherwise the default +is 1 (only the boot sector). +.TP +.BI \-s " sectors-per-cluster" +Specify the number of disk sectors per cluster. Must be a power of 2, +i.e. 1, 2, 4, 8, ... 128. +.TP +.BI \-S " logical-sector-size" +Specify the number of bytes per logical sector. Must be a power of 2 +and greater than or equal to 512, i.e. 512, 1024, 2048, 4096, 8192, +16384, or 32768. +.TP +.B \-v +Verbose execution. +.SH BUGS +.B mkdosfs +can not create boot-able file systems. This isn't as easy as you might +think at first glance for various reasons and has been discussed a lot +already. +.B mkdosfs +simply will not support it ;) +.SH AUTHOR +Dave Hudson - ; modified by Peter Anvin +. Fixes and additions by Roman Hodek + for Debian/GNU Linux. +.SH ACKNOWLEDGMENTS +.B mkdosfs +is based on code from +.BR mke2fs +(written by Remy Card - ) which is itself based on +.BR mkfs +(written by Linus Torvalds - ). +.SH SEE ALSO +.BR dosfsck (8), +.BR mkfs (8) diff --git a/src/Android.mk b/src/Android.mk new file mode 100644 index 0000000..a76a23a --- /dev/null +++ b/src/Android.mk @@ -0,0 +1,20 @@ +ifneq ($(TARGET_SIMULATOR), true) + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + boot.c check.c common.c fat.c file.c io.c lfn.c dosfsck.c + +LOCAL_C_INCLUDES := external/dosfstools/src + +LOCAL_CFLAGS := -O2 -g -W -Wall -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 + +LOCAL_MODULE := dosfsck +LOCAL_MODULE_TAGS := +LOCAL_SYSTEM_SHARED_LIBRARIES := libc + +include $(BUILD_EXECUTABLE) + +endif diff --git a/src/boot.c b/src/boot.c new file mode 100644 index 0000000..7048b7f --- /dev/null +++ b/src/boot.c @@ -0,0 +1,463 @@ +/* boot.c - Read and analyze ia PC/MS-DOS boot sector + + Copyright (C) 1993 Werner Almesberger + Copyright (C) 1998 Roman Hodek + + 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 3 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, see . + + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + +/* FAT32, VFAT, Atari format support, and various fixes additions May 1998 + * by Roman Hodek */ + +#include +#include +#include +#include +#include + +#include "common.h" +#include "dosfsck.h" +#include "io.h" +#include "boot.h" + + +#define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0) + /* don't divide by zero */ + +/* cut-over cluster counts for FAT12 and FAT16 */ +#define FAT12_THRESHOLD 4085 +#define FAT16_THRESHOLD 65525 + +static struct { + __u8 media; + char *descr; +} mediabytes[] = { + { 0xf0, "5.25\" or 3.5\" HD floppy" }, + { 0xf8, "hard disk" }, + { 0xf9, "3,5\" 720k floppy 2s/80tr/9sec or " + "5.25\" 1.2M floppy 2s/80tr/15sec" }, + { 0xfa, "5.25\" 320k floppy 1s/80tr/8sec" }, + { 0xfb, "3.5\" 640k floppy 2s/80tr/8sec" }, + { 0xfc, "5.25\" 180k floppy 1s/40tr/9sec" }, + { 0xfd, "5.25\" 360k floppy 2s/40tr/9sec" }, + { 0xfe, "5.25\" 160k floppy 1s/40tr/8sec" }, + { 0xff, "5.25\" 320k floppy 2s/40tr/8sec" }, +}; + +#if defined __alpha || defined __ia64__ || defined __s390x__ || defined __x86_64__ || defined __ppc64__ || defined __arm__ +/* Unaligned fields must first be copied byte-wise */ +#define GET_UNALIGNED_W(f) \ + ({ \ + unsigned short __v; \ + memcpy( &__v, &f, sizeof(__v) ); \ + CF_LE_W( *(unsigned short *)&__v ); \ + }) +#else +#define GET_UNALIGNED_W(f) CF_LE_W( *(unsigned short *)&f ) +#endif + +void die_notfat(char *msg,...) +{ + va_list args; + + va_start(args,msg); + vfprintf(stderr,msg,args); + va_end(args); + fprintf(stderr,"\n"); + exit(8); +} + + +static char *get_media_descr( unsigned char media ) +{ + unsigned int i; + + for( i = 0; i < sizeof(mediabytes)/sizeof(*mediabytes); ++i ) { + if (mediabytes[i].media == media) + return( mediabytes[i].descr ); + } + return( "undefined" ); +} + +static void dump_boot(DOS_FS *fs,struct boot_sector *b,unsigned lss) +{ + unsigned short sectors; + + printf("Boot sector contents:\n"); + if (!atari_format) { + char id[9]; + strncpy(id,b->system_id,8); + id[8] = 0; + printf("System ID \"%s\"\n",id); + } + else { + /* On Atari, a 24 bit serial number is stored at offset 8 of the boot + * sector */ + printf("Serial number 0x%x\n", + b->system_id[5] | (b->system_id[6]<<8) | (b->system_id[7]<<16)); + } + printf("Media byte 0x%02x (%s)\n",b->media,get_media_descr(b->media)); + printf("%10d bytes per logical sector\n",GET_UNALIGNED_W(b->sector_size)); + printf("%10d bytes per cluster\n",fs->cluster_size); + printf("%10d reserved sector%s\n",CF_LE_W(b->reserved), + CF_LE_W(b->reserved) == 1 ? "" : "s"); + printf("First FAT starts at byte %llu (sector %llu)\n", + (unsigned long long)fs->fat_start, + (unsigned long long)fs->fat_start/lss); + printf("%10d FATs, %d bit entries\n",b->fats,fs->fat_bits); + printf("%10d bytes per FAT (= %u sectors)\n",fs->fat_size, + fs->fat_size/lss); + if (!fs->root_cluster) { + printf("Root directory starts at byte %llu (sector %llu)\n", + (unsigned long long)fs->root_start, + (unsigned long long)fs->root_start/lss); + printf("%10d root directory entries\n",fs->root_entries); + } + else { + printf( "Root directory start at cluster %lu (arbitrary size)\n", + fs->root_cluster); + } + printf("Data area starts at byte %llu (sector %llu)\n", + (unsigned long long)fs->data_start, + (unsigned long long)fs->data_start/lss); + printf("%10lu data clusters (%llu bytes)\n",fs->clusters, + (unsigned long long)fs->clusters*fs->cluster_size); + printf("%u sectors/track, %u heads\n",CF_LE_W(b->secs_track), + CF_LE_W(b->heads)); + printf("%10u hidden sectors\n", + atari_format ? + /* On Atari, the hidden field is only 16 bit wide and unused */ + (((unsigned char *)&b->hidden)[0] | + ((unsigned char *)&b->hidden)[1] << 8) : + CF_LE_L(b->hidden)); + sectors = GET_UNALIGNED_W( b->sectors ); + printf("%10u sectors total\n", sectors ? sectors : CF_LE_L(b->total_sect)); +} + +static void check_backup_boot(DOS_FS *fs, struct boot_sector *b, int lss) +{ + struct boot_sector b2; + + if (!fs->backupboot_start) { + printf( "There is no backup boot sector.\n" ); + if (CF_LE_W(b->reserved) < 3) { + printf( "And there is no space for creating one!\n" ); + return; + } + if (interactive) + printf( "1) Create one\n2) Do without a backup\n" ); + else printf( " Auto-creating backup boot block.\n" ); + if (!interactive || get_key("12","?") == '1') { + int bbs; + /* The usual place for the backup boot sector is sector 6. Choose + * that or the last reserved sector. */ + if (CF_LE_W(b->reserved) >= 7 && CF_LE_W(b->info_sector) != 6) + bbs = 6; + else { + bbs = CF_LE_W(b->reserved) - 1; + if (bbs == CF_LE_W(b->info_sector)) + --bbs; /* this is never 0, as we checked reserved >= 3! */ + } + fs->backupboot_start = bbs*lss; + b->backup_boot = CT_LE_W(bbs); + fs_write(fs->backupboot_start,sizeof(*b),b); + fs_write((loff_t)offsetof(struct boot_sector,backup_boot), + sizeof(b->backup_boot),&b->backup_boot); + printf( "Created backup of boot sector in sector %d\n", bbs ); + return; + } + else return; + } + + fs_read(fs->backupboot_start,sizeof(b2),&b2); + if (memcmp(b,&b2,sizeof(b2)) != 0) { + /* there are any differences */ + __u8 *p, *q; + int i, pos, first = 1; + char buf[20]; + + printf( "There are differences between boot sector and its backup.\n" ); + printf( "Differences: (offset:original/backup)\n " ); + pos = 2; + for( p = (__u8 *)b, q = (__u8 *)&b2, i = 0; i < sizeof(b2); + ++p, ++q, ++i ) { + if (*p != *q) { + sprintf( buf, "%s%u:%02x/%02x", first ? "" : ", ", + (unsigned)(p-(__u8 *)b), *p, *q ); + if (pos + strlen(buf) > 78) printf( "\n " ), pos = 2; + printf( "%s", buf ); + pos += strlen(buf); + first = 0; + } + } + printf( "\n" ); + + if (interactive) + printf( "1) Copy original to backup\n" + "2) Copy backup to original\n" + "3) No action\n" ); + else printf( " Not automatically fixing this.\n" ); + switch (interactive ? get_key("123","?") : '3') { + case '1': + fs_write(fs->backupboot_start,sizeof(*b),b); + break; + case '2': + fs_write(0,sizeof(b2),&b2); + break; + default: + break; + } + } +} + +static void init_fsinfo(struct info_sector *i) +{ + i->magic = CT_LE_L(0x41615252); + i->signature = CT_LE_L(0x61417272); + i->free_clusters = CT_LE_L(-1); + i->next_cluster = CT_LE_L(2); + i->boot_sign = CT_LE_W(0xaa55); +} + +static void read_fsinfo(DOS_FS *fs, struct boot_sector *b,int lss) +{ + struct info_sector i; + + if (!b->info_sector) { + printf( "No FSINFO sector\n" ); + if (interactive) + printf( "1) Create one\n2) Do without FSINFO\n" ); + else printf( " Not automatically creating it.\n" ); + if (interactive && get_key("12","?") == '1') { + /* search for a free reserved sector (not boot sector and not + * backup boot sector) */ + __u32 s; + for( s = 1; s < CF_LE_W(b->reserved); ++s ) + if (s != CF_LE_W(b->backup_boot)) break; + if (s > 0 && s < CF_LE_W(b->reserved)) { + init_fsinfo(&i); + fs_write((loff_t)s*lss,sizeof(i),&i); + b->info_sector = CT_LE_W(s); + fs_write((loff_t)offsetof(struct boot_sector,info_sector), + sizeof(b->info_sector),&b->info_sector); + if (fs->backupboot_start) + fs_write(fs->backupboot_start+ + offsetof(struct boot_sector,info_sector), + sizeof(b->info_sector),&b->info_sector); + } + else { + printf( "No free reserved sector found -- " + "no space for FSINFO sector!\n" ); + return; + } + } + else return; + } + + fs->fsinfo_start = CF_LE_W(b->info_sector)*lss; + fs_read(fs->fsinfo_start,sizeof(i),&i); + + if (i.magic != CT_LE_L(0x41615252) || + i.signature != CT_LE_L(0x61417272) || + i.boot_sign != CT_LE_W(0xaa55)) { + printf( "FSINFO sector has bad magic number(s):\n" ); + if (i.magic != CT_LE_L(0x41615252)) + printf( " Offset %llu: 0x%08x != expected 0x%08x\n", + (unsigned long long)offsetof(struct info_sector,magic), + CF_LE_L(i.magic),0x41615252); + if (i.signature != CT_LE_L(0x61417272)) + printf( " Offset %llu: 0x%08x != expected 0x%08x\n", + (unsigned long long)offsetof(struct info_sector,signature), + CF_LE_L(i.signature),0x61417272); + if (i.boot_sign != CT_LE_W(0xaa55)) + printf( " Offset %llu: 0x%04x != expected 0x%04x\n", + (unsigned long long)offsetof(struct info_sector,boot_sign), + CF_LE_W(i.boot_sign),0xaa55); + if (interactive) + printf( "1) Correct\n2) Don't correct (FSINFO invalid then)\n" ); + else printf( " Auto-correcting it.\n" ); + if (!interactive || get_key("12","?") == '1') { + init_fsinfo(&i); + fs_write(fs->fsinfo_start,sizeof(i),&i); + } + else fs->fsinfo_start = 0; + } + + if (fs->fsinfo_start) + fs->free_clusters = CF_LE_L(i.free_clusters); +} + +void read_boot(DOS_FS *fs) +{ + struct boot_sector b; + unsigned total_sectors; + unsigned short logical_sector_size, sectors; + unsigned fat_length; + loff_t data_size; + + fs_read(0,sizeof(b),&b); + logical_sector_size = GET_UNALIGNED_W(b.sector_size); + if (!logical_sector_size) die_notfat("Logical sector size is zero."); + fs->cluster_size = b.cluster_size*logical_sector_size; + if (!fs->cluster_size) die_notfat("Cluster size is zero."); + if (b.fats != 2 && b.fats != 1) + die("Currently, only 1 or 2 FATs are supported, not %d.\n",b.fats); + fs->nfats = b.fats; + sectors = GET_UNALIGNED_W(b.sectors); + total_sectors = sectors ? sectors : CF_LE_L(b.total_sect); + + if (verbose) printf("Checking we can access the last sector of the filesystem\n"); + /* Can't access last odd sector anyway, so round down */ + fs_test((loff_t)((total_sectors & ~1)-1)*(loff_t)logical_sector_size, + logical_sector_size); + fat_length = CF_LE_W(b.fat_length) ? + CF_LE_W(b.fat_length) : CF_LE_L(b.fat32_length); + fs->fat_start = (loff_t)CF_LE_W(b.reserved)*logical_sector_size; + fs->root_start = ((loff_t)CF_LE_W(b.reserved)+b.fats*fat_length)* + logical_sector_size; + fs->root_entries = GET_UNALIGNED_W(b.dir_entries); + fs->data_start = fs->root_start+ROUND_TO_MULTIPLE(fs->root_entries << + MSDOS_DIR_BITS,logical_sector_size); + data_size = (loff_t)total_sectors*logical_sector_size-fs->data_start; + fs->clusters = data_size/fs->cluster_size; + fs->root_cluster = 0; /* indicates standard, pre-FAT32 root dir */ + fs->fsinfo_start = 0; /* no FSINFO structure */ + fs->free_clusters = -1; /* unknown */ + if (!b.fat_length && b.fat32_length) { + fs->fat_bits = 32; + fs->root_cluster = CF_LE_L(b.root_cluster); + if (!fs->root_cluster && fs->root_entries) + /* M$ hasn't specified this, but it looks reasonable: If + * root_cluster is 0 but there is a separate root dir + * (root_entries != 0), we handle the root dir the old way. Give a + * warning, but convertig to a root dir in a cluster chain seems + * to complex for now... */ + printf( "Warning: FAT32 root dir not in cluster chain! " + "Compability mode...\n" ); + else if (!fs->root_cluster && !fs->root_entries) + die_notfat("No root directory!"); + else if (fs->root_cluster && fs->root_entries) + printf( "Warning: FAT32 root dir is in a cluster chain, but " + "a separate root dir\n" + " area is defined. Cannot fix this easily.\n" ); + if (fs->clusters < FAT16_THRESHOLD) + printf("Warning: Filesystem is FAT32 according to fat_length " + "and fat32_length fields,\n" + " but has only %lu clusters, less than the required " + "minimum of %d.\n" + " This may lead to problems on some systems.\n", + fs->clusters, FAT16_THRESHOLD); + + fs->backupboot_start = CF_LE_W(b.backup_boot)*logical_sector_size; + check_backup_boot(fs,&b,logical_sector_size); + + read_fsinfo(fs,&b,logical_sector_size); + } + else if (!atari_format) { + /* On real MS-DOS, a 16 bit FAT is used whenever there would be too + * much clusers otherwise. */ + fs->fat_bits = (fs->clusters >= FAT12_THRESHOLD) ? 16 : 12; + if (fs->clusters >= FAT16_THRESHOLD) + die("Too many clusters (%lu) for FAT16 filesystem.", + fs->clusters); + } + else { + /* On Atari, things are more difficult: GEMDOS always uses 12bit FATs + * on floppies, and always 16 bit on harddisks. */ + fs->fat_bits = 16; /* assume 16 bit FAT for now */ + /* If more clusters than fat entries in 16-bit fat, we assume + * it's a real MSDOS FS with 12-bit fat. */ + if (fs->clusters+2 > fat_length*logical_sector_size*8/16 || + /* if it's a floppy disk --> 12bit fat */ + device_no == 2 || + /* if it's a ramdisk or loopback device and has one of the usual + * floppy sizes -> 12bit FAT */ + ((device_no == 1 || device_no == 7) && + (total_sectors == 720 || total_sectors == 1440 || + total_sectors == 2880))) + fs->fat_bits = 12; + } + /* On FAT32, the high 4 bits of a FAT entry are reserved */ + fs->eff_fat_bits = (fs->fat_bits == 32) ? 28 : fs->fat_bits; + fs->fat_size = fat_length*logical_sector_size; + + fs->label = calloc(12, sizeof (__u8)); + if (fs->fat_bits == 12 || fs->fat_bits == 16) { + struct boot_sector_16 *b16 = (struct boot_sector_16 *)&b; + if (b16->extended_sig == 0x29) + memmove(fs->label, b16->label, 11); + else + fs->label = NULL; + } else if (fs->fat_bits == 32) { + if (b.extended_sig == 0x29) + memmove(fs->label, &b.label, 11); + else + fs->label = NULL; + } + + if (fs->clusters > ((unsigned long long)fs->fat_size*8/fs->fat_bits)-2) + die("File system has %d clusters but only space for %d FAT entries.", + fs->clusters,((unsigned long long)fs->fat_size*8/fs->fat_bits)-2); + if (!fs->root_entries && !fs->root_cluster) + die("Root directory has zero size."); + if (fs->root_entries & (MSDOS_DPS-1)) + die("Root directory (%d entries) doesn't span an integral number of " + "sectors.",fs->root_entries); + if (logical_sector_size & (SECTOR_SIZE-1)) + die("Logical sector size (%d bytes) is not a multiple of the physical " + "sector size.",logical_sector_size); +#if 0 /* linux kernel doesn't check that either */ + /* ++roman: On Atari, these two fields are often left uninitialized */ + if (!atari_format && (!b.secs_track || !b.heads)) + die("Invalid disk format in boot sector."); +#endif + if (verbose) dump_boot(fs,&b,logical_sector_size); +} + +void write_label(DOS_FS *fs, char *label) +{ + struct boot_sector b; + struct boot_sector_16 *b16 = (struct boot_sector_16 *)&b; + int l = strlen(label); + + while (l < 11) + label[l++] = ' '; + + fs_read(0, sizeof(b), &b); + if (fs->fat_bits == 12 || fs->fat_bits == 16) { + if (b16->extended_sig != 0x29) { + b16->extended_sig = 0x29; + b16->serial = 0; + memmove(b16->fs_type, fs->fat_bits == 12 ?"FAT12 ":"FAT16 ", 8); + } + memmove(b16->label, label, 11); + } else if (fs->fat_bits == 32) { + if (b.extended_sig != 0x29) { + b.extended_sig = 0x29; + b.serial = 0; + memmove(b.fs_type, "FAT32 ", 8); + } + memmove(b.label, label, 11); + } + fs_write(0, sizeof(b), &b); + if (fs->fat_bits == 32 && fs->backupboot_start) + fs_write(fs->backupboot_start, sizeof(b), &b); +} + +/* Local Variables: */ +/* tab-width: 8 */ +/* End: */ diff --git a/src/boot.h b/src/boot.h new file mode 100644 index 0000000..eedf2b0 --- /dev/null +++ b/src/boot.h @@ -0,0 +1,31 @@ +/* boot.h - Read and analyze ia PC/MS-DOS boot sector + + Copyright (C) 1993 Werner Almesberger + + 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 3 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, see . + + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + + +#ifndef _BOOT_H +#define _BOOT_H + +void read_boot(DOS_FS *fs); +void write_label(DOS_FS *fs, char *label); + +/* Reads the boot sector from the currently open device and initializes *FS */ + +#endif diff --git a/src/check.c b/src/check.c new file mode 100644 index 0000000..870fcd9 --- /dev/null +++ b/src/check.c @@ -0,0 +1,883 @@ +/* check.c - Check and repair a PC/MS-DOS file system + + Copyright (C) 1993 Werner Almesberger + Copyright (C) 1998 Roman Hodek + + 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 3 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, see . + + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + +/* FAT32, VFAT, Atari format support, and various fixes additions May 1998 + * by Roman Hodek */ + + +#include +#include +#include +#include +#include + +#include "common.h" +#include "dosfsck.h" +#include "io.h" +#include "fat.h" +#include "file.h" +#include "lfn.h" +#include "check.h" + + +static DOS_FILE *root; + +/* get start field of a dir entry */ +#define FSTART(p,fs) \ + ((unsigned long)CF_LE_W(p->dir_ent.start) | \ + (fs->fat_bits == 32 ? CF_LE_W(p->dir_ent.starthi) << 16 : 0)) + +#define MODIFY(p,i,v) \ + do { \ + if (p->offset) { \ + p->dir_ent.i = v; \ + fs_write(p->offset+offsetof(DIR_ENT,i), \ + sizeof(p->dir_ent.i),&p->dir_ent.i); \ + } \ + } while(0) + +#define MODIFY_START(p,v,fs) \ + do { \ + unsigned long __v = (v); \ + if (!p->offset) { \ + /* writing to fake entry for FAT32 root dir */ \ + if (!__v) die("Oops, deleting FAT32 root dir!"); \ + fs->root_cluster = __v; \ + p->dir_ent.start = CT_LE_W(__v&0xffff); \ + p->dir_ent.starthi = CT_LE_W(__v>>16); \ + __v = CT_LE_L(__v); \ + fs_write((loff_t)offsetof(struct boot_sector,root_cluster), \ + sizeof(((struct boot_sector *)0)->root_cluster), \ + &__v); \ + } \ + else { \ + MODIFY(p,start,CT_LE_W((__v)&0xffff)); \ + if (fs->fat_bits == 32) \ + MODIFY(p,starthi,CT_LE_W((__v)>>16)); \ + } \ + } while(0) + + +loff_t alloc_rootdir_entry(DOS_FS *fs, DIR_ENT *de, const char *pattern) +{ + static int curr_num = 0; + loff_t offset; + + if (fs->root_cluster) { + DIR_ENT d2; + int i = 0, got = 0; + unsigned long clu_num, prev = 0; + loff_t offset2; + + clu_num = fs->root_cluster; + offset = cluster_start(fs,clu_num); + while (clu_num > 0 && clu_num != -1) { + fs_read(offset,sizeof(DIR_ENT),&d2); + if (IS_FREE(d2.name) && d2.attr != VFAT_LN_ATTR) { + got = 1; + break; + } + i += sizeof(DIR_ENT); + offset += sizeof(DIR_ENT); + if ((i % fs->cluster_size) == 0) { + prev = clu_num; + if ((clu_num = next_cluster(fs,clu_num)) == 0 || clu_num == -1) + break; + offset = cluster_start(fs,clu_num); + } + } + if (!got) { + /* no free slot, need to extend root dir: alloc next free cluster + * after previous one */ + if (!prev) + die("Root directory has no cluster allocated!"); + for (clu_num = prev+1; clu_num != prev; clu_num++) { + if (clu_num >= fs->clusters+2) clu_num = 2; + if (!fs->fat[clu_num].value) + break; + } + if (clu_num == prev) + die("Root directory full and no free cluster"); + set_fat(fs,prev,clu_num); + set_fat(fs,clu_num,-1); + set_owner(fs, clu_num, get_owner(fs, fs->root_cluster)); + /* clear new cluster */ + memset( &d2, 0, sizeof(d2) ); + offset = cluster_start(fs,clu_num); + for( i = 0; i < fs->cluster_size; i += sizeof(DIR_ENT) ) + fs_write( offset+i, sizeof(d2), &d2 ); + } + memset(de,0,sizeof(DIR_ENT)); + while (1) { + sprintf(de->name,pattern,curr_num); + clu_num = fs->root_cluster; + i = 0; + offset2 = cluster_start(fs,clu_num); + while (clu_num > 0 && clu_num != -1) { + fs_read(offset2,sizeof(DIR_ENT),&d2); + if (offset2 != offset && + !strncmp(d2.name,de->name,MSDOS_NAME)) + break; + i += sizeof(DIR_ENT); + offset2 += sizeof(DIR_ENT); + if ((i % fs->cluster_size) == 0) { + if ((clu_num = next_cluster(fs,clu_num)) == 0 || + clu_num == -1) + break; + offset2 = cluster_start(fs,clu_num); + } + } + if (clu_num == 0 || clu_num == -1) + break; + if (++curr_num >= 10000) die("Unable to create unique name"); + } + } + else { + DIR_ENT *root; + int next_free = 0, scan; + + root = alloc(fs->root_entries*sizeof(DIR_ENT)); + fs_read(fs->root_start,fs->root_entries*sizeof(DIR_ENT),root); + + while (next_free < fs->root_entries) + if (IS_FREE(root[next_free].name) && + root[next_free].attr != VFAT_LN_ATTR) + break; + else next_free++; + if (next_free == fs->root_entries) + die("Root directory is full."); + offset = fs->root_start+next_free*sizeof(DIR_ENT); + memset(de,0,sizeof(DIR_ENT)); + while (1) { + sprintf(de->name,pattern,curr_num); + for (scan = 0; scan < fs->root_entries; scan++) + if (scan != next_free && + !strncmp(root[scan].name,de->name,MSDOS_NAME)) + break; + if (scan == fs->root_entries) break; + if (++curr_num >= 10000) die("Unable to create unique name"); + } + free(root); + } + ++n_files; + return offset; +} + + +static char *path_name(DOS_FILE *file) +{ + static char path[PATH_MAX*2]; + + if (!file) *path = 0; + else { + if (strlen(path_name(file->parent)) > PATH_MAX) + die("Path name too long."); + if (strcmp(path,"/") != 0) strcat(path,"/"); + strcpy(strrchr(path,0),file->lfn?file->lfn:file_name(file->dir_ent.name)); + } + return path; +} + + +static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 }; + /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */ + + +/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ + +time_t date_dos2unix(unsigned short time,unsigned short date) +{ + int month,year; + time_t secs; + + month = ((date >> 5) & 15)-1; + year = date >> 9; + secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400* + ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 && + month < 2 ? 1 : 0)+3653); + /* days since 1.1.70 plus 80's leap day */ + return secs; +} + + +static char *file_stat(DOS_FILE *file) +{ + static char temp[100]; + struct tm *tm; + char tmp[100]; + time_t date; + + date = date_dos2unix(CF_LE_W(file->dir_ent.time),CF_LE_W(file-> + dir_ent.date)); + tm = localtime(&date); + strftime(tmp,99,"%H:%M:%S %b %d %Y",tm); + sprintf(temp," Size %u bytes, date %s",CF_LE_L(file->dir_ent.size),tmp); + return temp; +} + + +static int bad_name(unsigned char *name) +{ + int i, spc, suspicious = 0; + char *bad_chars = atari_format ? "*?\\/:" : "*?<>|\"\\/:"; + + /* Do not complain about (and auto-correct) the extended attribute files + * of OS/2. */ + if (strncmp(name,"EA DATA SF",11) == 0 || + strncmp(name,"WP ROOT SF",11) == 0) return 0; + + for (i = 0; i < 8; i++) { + if (name[i] < ' ' || name[i] == 0x7f) return 1; + if (name[i] > 0x7f) ++suspicious; + if (strchr(bad_chars,name[i])) return 1; + } + + for (i = 8; i < 11; i++) { + if (name[i] < ' ' || name[i] == 0x7f) return 1; + if (name[i] > 0x7f) ++suspicious; + if (strchr(bad_chars,name[i])) return 1; + } + + spc = 0; + for (i = 0; i < 8; i++) { + if (name[i] == ' ') + spc = 1; + else if (spc) + /* non-space after a space not allowed, space terminates the name + * part */ + return 1; + } + + spc = 0; + for (i = 8; i < 11; i++) { + if (name[i] == ' ') + spc = 1; + else if (spc) + /* non-space after a space not allowed, space terminates the name + * part */ + return 1; + } + + /* Under GEMDOS, chars >= 128 are never allowed. */ + if (atari_format && suspicious) + return 1; + + /* Only complain about too much suspicious chars in interactive mode, + * never correct them automatically. The chars are all basically ok, so we + * shouldn't auto-correct such names. */ + if (interactive && suspicious > 6) + return 1; + return 0; +} + + +static void drop_file(DOS_FS *fs,DOS_FILE *file) +{ + unsigned long cluster; + + MODIFY(file,name[0],DELETED_FLAG); + for (cluster = FSTART(file,fs); cluster > 0 && cluster < + fs->clusters+2; cluster = next_cluster(fs,cluster)) + set_owner(fs,cluster,NULL); + --n_files; +} + + +static void truncate_file(DOS_FS *fs,DOS_FILE *file,unsigned long clusters) +{ + int deleting; + unsigned long walk,next,prev; + + walk = FSTART(file,fs); + prev = 0; + if ((deleting = !clusters)) MODIFY_START(file,0,fs); + while (walk > 0 && walk != -1) { + next = next_cluster(fs,walk); + if (deleting) set_fat(fs,walk,0); + else if ((deleting = !--clusters)) set_fat(fs,walk,-1); + prev = walk; + walk = next; + } +} + + +static void auto_rename(DOS_FILE *file) +{ + DOS_FILE *first,*walk; + unsigned long int number; + + if (!file->offset) return; /* cannot rename FAT32 root dir */ + first = file->parent ? file->parent->first : root; + number = 0; + while (1) { + sprintf(file->dir_ent.name, "FSCK%04d", number / 1000); + sprintf(file->dir_ent.name, "%03d", number % 1000); + for (walk = first; walk; walk = walk->next) + if (walk != file && !strncmp(walk->dir_ent.name,file->dir_ent. + name,MSDOS_NAME)) break; + if (!walk) { + fs_write(file->offset,MSDOS_NAME,file->dir_ent.name); + return; + } + number++; + if (number > 9999999) { + die("Too many files need repair."); + } + } + die("Can't generate a unique name."); +} + + +static void rename_file(DOS_FILE *file) +{ + unsigned char name[46]; + unsigned char *walk,*here; + + if (!file->offset) { + printf( "Cannot rename FAT32 root dir\n" ); + return; /* cannot rename FAT32 root dir */ + } + while (1) { + printf("New name: "); + fflush(stdout); + if (fgets(name,45,stdin)) { + if ((here = strchr(name,'\n'))) *here = 0; + for (walk = strrchr(name,0); walk >= name && (*walk == ' ' || + *walk == '\t'); walk--); + walk[1] = 0; + for (walk = name; *walk == ' ' || *walk == '\t'; walk++); + if (file_cvt(walk,file->dir_ent.name)) { + fs_write(file->offset,MSDOS_NAME,file->dir_ent.name); + return; + } + } + } +} + + +static int handle_dot(DOS_FS *fs,DOS_FILE *file,int dots) +{ + char *name; + + name = strncmp(file->dir_ent.name,MSDOS_DOT,MSDOS_NAME) ? ".." : "."; + if (!(file->dir_ent.attr & ATTR_DIR)) { + printf("%s\n Is a non-directory.\n",path_name(file)); + if (interactive) + printf("1) Drop it\n2) Auto-rename\n3) Rename\n" + "4) Convert to directory\n"); + else printf(" Auto-renaming it.\n"); + switch (interactive ? get_key("1234","?") : '2') { + case '1': + drop_file(fs,file); + return 1; + case '2': + auto_rename(file); + printf(" Renamed to %s\n",file_name(file->dir_ent.name)); + return 0; + case '3': + rename_file(file); + return 0; + case '4': + MODIFY(file,size,CT_LE_L(0)); + MODIFY(file,attr,file->dir_ent.attr | ATTR_DIR); + break; + } + } + if (!dots) { + printf("Root contains directory \"%s\". Dropping it.\n",name); + drop_file(fs,file); + return 1; + } + return 0; +} + + +static int check_file(DOS_FS *fs,DOS_FILE *file) +{ + DOS_FILE *owner; + int restart; + unsigned long expect,curr,this,clusters,prev,walk,clusters2; + + if (file->dir_ent.attr & ATTR_DIR) { + if (CF_LE_L(file->dir_ent.size)) { + printf("%s\n Directory has non-zero size. Fixing it.\n", + path_name(file)); + MODIFY(file,size,CT_LE_L(0)); + } + if (file->parent && !strncmp(file->dir_ent.name,MSDOS_DOT,MSDOS_NAME)) { + expect = FSTART(file->parent,fs); + if (FSTART(file,fs) != expect) { + printf("%s\n Start (%ld) does not point to parent (%ld)\n", + path_name(file),FSTART(file,fs),expect); + MODIFY_START(file,expect,fs); + } + return 0; + } + if (file->parent && !strncmp(file->dir_ent.name,MSDOS_DOTDOT, + MSDOS_NAME)) { + expect = file->parent->parent ? FSTART(file->parent->parent,fs):0; + if (fs->root_cluster && expect == fs->root_cluster) + expect = 0; + if (FSTART(file,fs) != expect) { + printf("%s\n Start (%lu) does not point to .. (%lu)\n", + path_name(file),FSTART(file,fs),expect); + MODIFY_START(file,expect,fs); + } + return 0; + } + if (FSTART(file,fs)==0){ + printf ("%s\n Start does point to root directory. Deleting dir. \n", + path_name(file)); + MODIFY(file,name[0],DELETED_FLAG); + return 0; + } + } + if (FSTART(file,fs) >= fs->clusters+2) { + printf("%s\n Start cluster beyond limit (%lu > %lu). Truncating file.\n", + path_name(file),FSTART(file,fs),fs->clusters+1); + if (!file->offset) + die( "Bad FAT32 root directory! (bad start cluster)\n" ); + MODIFY_START(file,0,fs); + } + clusters = prev = 0; + for (curr = FSTART(file,fs) ? FSTART(file,fs) : + -1; curr != -1; curr = next_cluster(fs,curr)) { + if (!fs->fat[curr].value || bad_cluster(fs,curr)) { + printf("%s\n Contains a %s cluster (%lu). Assuming EOF.\n", + path_name(file),fs->fat[curr].value ? "bad" : "free",curr); + if (prev) set_fat(fs,prev,-1); + else if (!file->offset) + die( "FAT32 root dir starts with a bad cluster!" ); + else MODIFY_START(file,0,fs); + break; + } + if (!(file->dir_ent.attr & ATTR_DIR) && CF_LE_L(file->dir_ent.size) <= + (unsigned long long)clusters*fs->cluster_size) { + printf("%s\n File size is %u bytes, cluster chain length is > %llu " + "bytes.\n Truncating file to %u bytes.\n",path_name(file), + CF_LE_L(file->dir_ent.size),(unsigned long long)clusters*fs->cluster_size, + CF_LE_L(file->dir_ent.size)); + truncate_file(fs,file,clusters); + break; + } + if ((owner = get_owner(fs,curr))) { + int do_trunc = 0; + printf("%s and\n",path_name(owner)); + printf("%s\n share clusters.\n",path_name(file)); + clusters2 = 0; + for (walk = FSTART(owner,fs); walk > 0 && walk != -1; walk = + next_cluster(fs,walk)) + if (walk == curr) break; + else clusters2++; + restart = file->dir_ent.attr & ATTR_DIR; + if (!owner->offset) { + printf( " Truncating second to %llu bytes because first " + "is FAT32 root dir.\n", (unsigned long long)clusters2*fs->cluster_size ); + do_trunc = 2; + } + else if (!file->offset) { + printf( " Truncating first to %llu bytes because second " + "is FAT32 root dir.\n", (unsigned long long)clusters*fs->cluster_size ); + do_trunc = 1; + } + else if (interactive) + printf("1) Truncate first to %llu bytes%s\n" + "2) Truncate second to %llu bytes\n",(unsigned long long)clusters*fs->cluster_size, + restart ? " and restart" : "",(unsigned long long)clusters2*fs->cluster_size); + else printf(" Truncating second to %llu bytes.\n",(unsigned long long)clusters2* + fs->cluster_size); + if (do_trunc != 2 && + (do_trunc == 1 || + (interactive && get_key("12","?") == '1'))) { + prev = 0; + clusters = 0; + for (this = FSTART(owner,fs); this > 0 && this != -1; this = + next_cluster(fs,this)) { + if (this == curr) { + if (prev) set_fat(fs,prev,-1); + else MODIFY_START(owner,0,fs); + MODIFY(owner,size,CT_LE_L((unsigned long long)clusters*fs->cluster_size)); + if (restart) return 1; + while (this > 0 && this != -1) { + set_owner(fs,this,NULL); + this = next_cluster(fs,this); + } + this = curr; + break; + } + clusters++; + prev = this; + } + if (this != curr) + die("Internal error: didn't find cluster %d in chain" + " starting at %d",curr,FSTART(owner,fs)); + } + else { + if (prev) set_fat(fs,prev,-1); + else MODIFY_START(file,0,fs); + break; + } + } + set_owner(fs,curr,file); + clusters++; + prev = curr; + } + if (!(file->dir_ent.attr & ATTR_DIR) && CF_LE_L(file->dir_ent.size) > + (unsigned long long)clusters*fs->cluster_size) { + printf("%s\n File size is %u bytes, cluster chain length is %llu bytes." + "\n Truncating file to %lu bytes.\n",path_name(file),CF_LE_L(file-> + dir_ent.size),(unsigned long long)clusters*fs->cluster_size,(unsigned long long)clusters*fs->cluster_size); + MODIFY(file,size,CT_LE_L((unsigned long long)clusters*fs->cluster_size)); + } + return 0; +} + + +static int check_files(DOS_FS *fs,DOS_FILE *start) +{ + while (start) { + if (check_file(fs,start)) return 1; + start = start->next; + } + return 0; +} + + +static int check_dir(DOS_FS *fs,DOS_FILE **root,int dots) +{ + DOS_FILE *parent,**walk,**scan; + int dot,dotdot,skip,redo; + int good,bad; + + if (!*root) return 0; + parent = (*root)->parent; + good = bad = 0; + for (walk = root; *walk; walk = &(*walk)->next) + if (bad_name((*walk)->dir_ent.name)) bad++; + else good++; + if (*root && parent && good+bad > 4 && bad > good/2) { + printf("%s\n Has a large number of bad entries. (%d/%d)\n", + path_name(parent),bad,good+bad); + if (!dots) printf( " Not dropping root directory.\n" ); + else if (!interactive) printf(" Not dropping it in auto-mode.\n"); + else if (get_key("yn","Drop directory ? (y/n)") == 'y') { + truncate_file(fs,parent,0); + MODIFY(parent,name[0],DELETED_FLAG); + /* buglet: deleted directory stays in the list. */ + return 1; + } + } + dot = dotdot = redo = 0; + walk = root; + while (*walk) { + if (!strncmp((*walk)->dir_ent.name,MSDOS_DOT,MSDOS_NAME) || + !strncmp((*walk)->dir_ent.name,MSDOS_DOTDOT,MSDOS_NAME)) { + if (handle_dot(fs,*walk,dots)) { + *walk = (*walk)->next; + continue; + } + if (!strncmp((*walk)->dir_ent.name,MSDOS_DOT,MSDOS_NAME)) dot++; + else dotdot++; + } + if (!((*walk)->dir_ent.attr & ATTR_VOLUME) && + bad_name((*walk)->dir_ent.name)) { + printf("%s\n Bad file name.\n",path_name(*walk)); + if (interactive) + printf("1) Drop file\n2) Rename file\n3) Auto-rename\n" + "4) Keep it\n"); + else printf(" Auto-renaming it.\n"); + switch (interactive ? get_key("1234","?") : '3') { + case '1': + drop_file(fs,*walk); + walk = &(*walk)->next; + continue; + case '2': + rename_file(*walk); + redo = 1; + break; + case '3': + auto_rename(*walk); + printf(" Renamed to %s\n",file_name((*walk)->dir_ent. + name)); + break; + case '4': + break; + } + } + /* don't check for duplicates of the volume label */ + if (!((*walk)->dir_ent.attr & ATTR_VOLUME)) { + scan = &(*walk)->next; + skip = 0; + while (*scan && !skip) { + if (!((*scan)->dir_ent.attr & ATTR_VOLUME) && + !strncmp((*walk)->dir_ent.name,(*scan)->dir_ent.name,MSDOS_NAME)) { + printf("%s\n Duplicate directory entry.\n First %s\n", + path_name(*walk),file_stat(*walk)); + printf(" Second %s\n",file_stat(*scan)); + if (interactive) + printf("1) Drop first\n2) Drop second\n3) Rename first\n" + "4) Rename second\n5) Auto-rename first\n" + "6) Auto-rename second\n"); + else printf(" Auto-renaming second.\n"); + switch (interactive ? get_key("123456","?") : '6') { + case '1': + drop_file(fs,*walk); + *walk = (*walk)->next; + skip = 1; + break; + case '2': + drop_file(fs,*scan); + *scan = (*scan)->next; + continue; + case '3': + rename_file(*walk); + printf(" Renamed to %s\n",path_name(*walk)); + redo = 1; + break; + case '4': + rename_file(*scan); + printf(" Renamed to %s\n",path_name(*walk)); + redo = 1; + break; + case '5': + auto_rename(*walk); + printf(" Renamed to %s\n",file_name((*walk)->dir_ent. + name)); + break; + case '6': + auto_rename(*scan); + printf(" Renamed to %s\n",file_name((*scan)->dir_ent. + name)); + break; + } + } + scan = &(*scan)->next; + } + if (skip) continue; + } + if (!redo) walk = &(*walk)->next; + else { + walk = root; + dot = dotdot = redo = 0; + } + } + if (dots && !dot) + printf("%s\n \".\" is missing. Can't fix this yet.\n", + path_name(parent)); + if (dots && !dotdot) + printf("%s\n \"..\" is missing. Can't fix this yet.\n", + path_name(parent)); + return 0; +} + + +static void test_file(DOS_FS *fs,DOS_FILE *file,int read_test) +{ + DOS_FILE *owner; + unsigned long walk,prev,clusters,next_clu; + + prev = clusters = 0; + for (walk = FSTART(file,fs); walk > 0 && walk < fs->clusters+2; + walk = next_clu) { + next_clu = next_cluster(fs,walk); + if ((owner = get_owner(fs,walk))) { + if (owner == file) { + printf("%s\n Circular cluster chain. Truncating to %lu " + "cluster%s.\n",path_name(file),clusters,clusters == 1 ? "" : + "s"); + if (prev) set_fat(fs,prev,-1); + else if (!file->offset) + die( "Bad FAT32 root directory! (bad start cluster)\n" ); + else MODIFY_START(file,0,fs); + } + break; + } + if (bad_cluster(fs,walk)) break; + if (read_test) { + if (fs_test(cluster_start(fs,walk),fs->cluster_size)) { + prev = walk; + clusters++; + } + else { + printf("%s\n Cluster %lu (%lu) is unreadable. Skipping it.\n", + path_name(file),clusters,walk); + if (prev) set_fat(fs,prev,next_cluster(fs,walk)); + else MODIFY_START(file,next_cluster(fs,walk),fs); + set_fat(fs,walk,-2); + } + } + set_owner(fs,walk,file); + } + for (walk = FSTART(file,fs); walk > 0 && walk < fs->clusters+2; + walk = next_cluster(fs,walk)) + if (bad_cluster(fs,walk)) break; + else if (get_owner(fs,walk) == file) set_owner(fs,walk,NULL); + else break; +} + + +static void undelete(DOS_FS *fs,DOS_FILE *file) +{ + unsigned long clusters,left,prev,walk; + + clusters = left = (CF_LE_L(file->dir_ent.size)+fs->cluster_size-1)/ + fs->cluster_size; + prev = 0; + for (walk = FSTART(file,fs); left && walk >= 2 && walk < + fs->clusters+2 && !fs->fat[walk].value; walk++) { + left--; + if (prev) set_fat(fs,prev,walk); + prev = walk; + } + if (prev) set_fat(fs,prev,-1); + else MODIFY_START(file,0,fs); + if (left) + printf("Warning: Did only undelete %lu of %lu cluster%s.\n",clusters-left, + clusters,clusters == 1 ? "" : "s"); + +} + + +static void new_dir( void ) +{ + lfn_reset(); +} + + +static void add_file(DOS_FS *fs,DOS_FILE ***chain,DOS_FILE *parent, + loff_t offset,FDSC **cp) +{ + DOS_FILE *new; + DIR_ENT de; + FD_TYPE type; + + if (offset) + fs_read(offset,sizeof(DIR_ENT),&de); + else { + memcpy(de.name," ",MSDOS_NAME); + de.attr = ATTR_DIR; + de.size = de.time = de.date = 0; + de.start = CT_LE_W(fs->root_cluster & 0xffff); + de.starthi = CT_LE_W((fs->root_cluster >> 16) & 0xffff); + } + if ((type = file_type(cp,de.name)) != fdt_none) { + if (type == fdt_undelete && (de.attr & ATTR_DIR)) + die("Can't undelete directories."); + file_modify(cp,de.name); + fs_write(offset,1,&de); + } + if (IS_FREE(de.name)) { + lfn_check_orphaned(); + return; + } + if (de.attr == VFAT_LN_ATTR) { + lfn_add_slot(&de,offset); + return; + } + new = qalloc(&mem_queue,sizeof(DOS_FILE)); + new->lfn = lfn_get(&de); + new->offset = offset; + memcpy(&new->dir_ent,&de,sizeof(de)); + new->next = new->first = NULL; + new->parent = parent; + if (type == fdt_undelete) undelete(fs,new); + **chain = new; + *chain = &new->next; + if (list) { + printf("Checking file %s",path_name(new)); + if (new->lfn) + printf(" (%s)", file_name(new->dir_ent.name) ); + printf("\n"); + } + if (offset && + strncmp(de.name,MSDOS_DOT,MSDOS_NAME) != 0 && + strncmp(de.name,MSDOS_DOTDOT,MSDOS_NAME) != 0) + ++n_files; + test_file(fs,new,test); +} + + +static int subdirs(DOS_FS *fs,DOS_FILE *parent,FDSC **cp); + + +static int scan_dir(DOS_FS *fs,DOS_FILE *this,FDSC **cp) +{ + DOS_FILE **chain; + int i; + unsigned long clu_num; + + chain = &this->first; + i = 0; + clu_num = FSTART(this,fs); + new_dir(); + while (clu_num > 0 && clu_num != -1) { + add_file(fs,&chain,this,cluster_start(fs,clu_num)+(i % fs-> + cluster_size),cp); + i += sizeof(DIR_ENT); + if (!(i % fs->cluster_size)) + if ((clu_num = next_cluster(fs,clu_num)) == 0 || clu_num == -1) + break; + } + lfn_check_orphaned(); + if (check_dir(fs,&this->first,this->offset)) return 0; + if (check_files(fs,this->first)) return 1; + return subdirs(fs,this,cp); +} + + +static int subdirs(DOS_FS *fs,DOS_FILE *parent,FDSC **cp) +{ + DOS_FILE *walk; + + for (walk = parent ? parent->first : root; walk; walk = walk->next) + if (walk->dir_ent.attr & ATTR_DIR) + if (strncmp(walk->dir_ent.name,MSDOS_DOT,MSDOS_NAME) && + strncmp(walk->dir_ent.name,MSDOS_DOTDOT,MSDOS_NAME)) + if (scan_dir(fs,walk,file_cd(cp,walk->dir_ent.name))) return 1; + return 0; +} + + +int scan_root(DOS_FS *fs) +{ + DOS_FILE **chain; + int i; + + root = NULL; + chain = &root; + new_dir(); + if (fs->root_cluster) { + add_file(fs,&chain,NULL,0,&fp_root); + } + else { + for (i = 0; i < fs->root_entries; i++) + add_file(fs,&chain,NULL,fs->root_start+i*sizeof(DIR_ENT),&fp_root); + } + lfn_check_orphaned(); + (void) check_dir(fs,&root,0); + if (check_files(fs,root)) return 1; + return subdirs(fs,NULL,&fp_root); +} + +/* Local Variables: */ +/* tab-width: 8 */ +/* End: */ diff --git a/src/check.h b/src/check.h new file mode 100644 index 0000000..a41bb86 --- /dev/null +++ b/src/check.h @@ -0,0 +1,40 @@ +/* check.h - Check and repair a PC/MS-DOS file system + + Copyright (C) 1993 Werner Almesberger + + 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 3 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, see . + + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + + +#ifndef _CHECK_H +#define _CHECK_H + +loff_t alloc_rootdir_entry(DOS_FS *fs, DIR_ENT *de, const char *pattern); + +/* Allocate a free slot in the root directory for a new file. The file name is + constructed after 'pattern', which must include a %d type format for printf + and expand to exactly 11 characters. The name actually used is written into + the 'de' structure, the rest of *de is cleared. The offset returned is to + where in the filesystem the entry belongs. */ + +int scan_root(DOS_FS *fs); + +/* Scans the root directory and recurses into all subdirectories. See check.c + for all the details. Returns a non-zero integer if the file system has to + be checked again. */ + +#endif diff --git a/src/common.c b/src/common.c new file mode 100644 index 0000000..92312e4 --- /dev/null +++ b/src/common.c @@ -0,0 +1,125 @@ +/* common.c - Common functions + + Copyright (C) 1993 Werner Almesberger + Copyright (C) 1998 Roman Hodek + + 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 3 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, see . + + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + +/* FAT32, VFAT, Atari format support, and various fixes additions May 1998 + * by Roman Hodek */ + + +#include +#include +#include +#include +#include + +#include "common.h" + + +typedef struct _link { + void *data; + struct _link *next; +} LINK; + + +void die(char *msg,...) +{ + va_list args; + + va_start(args,msg); + vfprintf(stderr,msg,args); + va_end(args); + fprintf(stderr,"\n"); + exit(1); +} + + +void pdie(char *msg,...) +{ + va_list args; + + va_start(args,msg); + vfprintf(stderr,msg,args); + va_end(args); + fprintf(stderr,":%s\n",strerror(errno)); + exit(1); +} + + +void *alloc(int size) +{ + void *this; + + if ((this = malloc(size))) return this; + pdie("malloc"); + return NULL; /* for GCC */ +} + + +void *qalloc(void **root,int size) +{ + LINK *link; + + link = alloc(sizeof(LINK)); + link->next = *root; + *root = link; + return link->data = alloc(size); +} + + +void qfree(void **root) +{ + LINK *this; + + while (*root) { + this = (LINK *) *root; + *root = this->next; + free(this->data); + free(this); + } +} + + +int min(int a,int b) +{ + return a < b ? a : b; +} + + +char get_key(char *valid,char *prompt) +{ + int ch,okay; + + while (1) { + if (prompt) printf("%s ",prompt); + fflush(stdout); + while (ch = getchar(), ch == ' ' || ch == '\t'); + if (ch == EOF) exit(1); + if (!strchr(valid,okay = ch)) okay = 0; + while (ch = getchar(), ch != '\n' && ch != EOF); + if (ch == EOF) exit(1); + if (okay) return okay; + printf("Invalid input.\n"); + } +} + +/* Local Variables: */ +/* tab-width: 8 */ +/* End: */ diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..99e0be1 --- /dev/null +++ b/src/common.h @@ -0,0 +1,57 @@ +/* common.h - Common functions + + Copyright (C) 1993 Werner Almesberger + + 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 3 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, see . + + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + +# include + +#ifndef _COMMON_H +#define _COMMON_H + +void die(char *msg,...) __attribute((noreturn)); + +/* Displays a prinf-style message and terminates the program. */ + +void pdie(char *msg,...) __attribute((noreturn)); + +/* Like die, but appends an error message according to the state of errno. */ + +void *alloc(int size); + +/* mallocs SIZE bytes and returns a pointer to the data. Terminates the program + if malloc fails. */ + +void *qalloc(void **root,int size); + +/* Like alloc, but registers the data area in a list described by ROOT. */ + +void qfree(void **root); + +/* Deallocates all qalloc'ed data areas described by ROOT. */ + +int min(int a,int b); + +/* Returns the smaller integer value of a and b. */ + +char get_key(char *valid,char *prompt); + +/* Displays PROMPT and waits for user input. Only characters in VALID are + accepted. Terminates the program on EOF. Returns the character. */ + +#endif diff --git a/src/dosfsck.c b/src/dosfsck.c new file mode 100644 index 0000000..c4bcf1b --- /dev/null +++ b/src/dosfsck.c @@ -0,0 +1,207 @@ +/* dosfsck.c - User interface + + Copyright (C) 1993 Werner Almesberger + Copyright (C) 1998 Roman Hodek + + 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 3 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, see . + + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + +/* FAT32, VFAT, Atari format support, and various fixes additions May 1998 + * by Roman Hodek */ + + +#include "version.h" + +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "dosfsck.h" +#include "io.h" +#include "boot.h" +#include "fat.h" +#include "file.h" +#include "check.h" + + +int interactive = 0,list = 0,test = 0,verbose = 0,write_immed = 0; +int atari_format = 0; +unsigned n_files = 0; +void *mem_queue = NULL; + + +static void usage(char *name) +{ + fprintf(stderr,"usage: %s [-aAflrtvVwy] [-d path -d ...] " + "[-u path -u ...]\n%15sdevice\n",name,""); + fprintf(stderr," -a automatically repair the file system\n"); + fprintf(stderr," -A toggle Atari file system format\n"); + fprintf(stderr," -d path drop that file\n"); + fprintf(stderr," -f salvage unused chains to files\n"); + fprintf(stderr," -l list path names\n"); + fprintf(stderr," -n no-op, check non-interactively without changing\n"); + fprintf(stderr," -p same as -a, for compat with other *fsck\n"); + fprintf(stderr," -r interactively repair the file system\n"); + fprintf(stderr," -t test for bad clusters\n"); + fprintf(stderr," -u path try to undelete that (non-directory) file\n"); + fprintf(stderr," -v verbose mode\n"); + fprintf(stderr," -V perform a verification pass\n"); + fprintf(stderr," -w write changes to disk immediately\n"); + fprintf(stderr," -y same as -a, for compat with other *fsck\n"); + exit(2); +} + + +/* + * ++roman: On m68k, check if this is an Atari; if yes, turn on Atari variant + * of MS-DOS filesystem by default. + */ +static void check_atari( void ) +{ +#ifdef __mc68000__ + FILE *f; + char line[128], *p; + + if (!(f = fopen( "/proc/hardware", "r" ))) { + perror( "/proc/hardware" ); + return; + } + + while( fgets( line, sizeof(line), f ) ) { + if (strncmp( line, "Model:", 6 ) == 0) { + p = line + 6; + p += strspn( p, " \t" ); + if (strncmp( p, "Atari ", 6 ) == 0) + atari_format = 1; + break; + } + } + fclose( f ); +#endif +} + + +int main(int argc,char **argv) +{ + DOS_FS fs; + int rw,salvage_files,verify,c; + unsigned n_files_check=0, n_files_verify=0; + unsigned long free_clusters; + + rw = salvage_files = verify = 0; + interactive = 1; + check_atari(); + + while ((c = getopt(argc,argv,"Aad:flnprtu:vVwy")) != EOF) + switch (c) { + case 'A': /* toggle Atari format */ + atari_format = !atari_format; + break; + case 'a': + case 'p': + case 'y': + rw = 1; + interactive = 0; +// salvage_files = 1; + break; + case 'd': + file_add(optarg,fdt_drop); + break; + case 'f': + salvage_files = 1; + break; + case 'l': + list = 1; + break; + case 'n': + rw = 0; + interactive = 0; + break; + case 'r': + rw = 1; + interactive = 1; + break; + case 't': + test = 1; + break; + case 'u': + file_add(optarg,fdt_undelete); + break; + case 'v': + verbose = 1; + printf("dosfsck " VERSION " (" VERSION_DATE ")\n"); + break; + case 'V': + verify = 1; + break; + case 'w': + write_immed = 1; + break; + default: + usage(argv[0]); + } + if ((test || write_immed) && !rw) { + fprintf(stderr,"-t and -w require -a or -r\n"); + exit(2); + } + if (optind != argc-1) usage(argv[0]); + + printf( "dosfsck " VERSION ", " VERSION_DATE ", FAT32, LFN\n" ); + fs_open(argv[optind],rw); + read_boot(&fs); + if (verify) printf("Starting check/repair pass.\n"); + while (read_fat(&fs), scan_root(&fs)) qfree(&mem_queue); + if (test) fix_bad(&fs); + if (salvage_files) reclaim_file(&fs); + else reclaim_free(&fs); + free_clusters = update_free(&fs); + file_unused(); + qfree(&mem_queue); + n_files_check = n_files; + if (verify) { + n_files = 0; + printf("Starting verification pass.\n"); + read_fat(&fs); + scan_root(&fs); + reclaim_free(&fs); + qfree(&mem_queue); + n_files_verify = n_files; + } + + if (fs_changed()) { + if (rw) { + if (interactive) + rw = get_key("yn","Perform changes ? (y/n)") == 'y'; + else printf("Performing changes.\n"); + } + else + printf("Leaving file system unchanged.\n"); + } + + printf( "%s: %u files, %lu/%lu clusters\n", argv[optind], + n_files, fs.clusters - free_clusters, fs.clusters ); + + exit(fs_close(rw) ? 4 : 0); +} + +/* Local Variables: */ +/* tab-width: 8 */ +/* End: */ diff --git a/src/dosfsck.h b/src/dosfsck.h new file mode 100644 index 0000000..3d2004c --- /dev/null +++ b/src/dosfsck.h @@ -0,0 +1,220 @@ +/* dosfsck.h - Common data structures and global variables + + Copyright (C) 1993 Werner Almesberger + Copyright (C) 1998 Roman Hodek + + 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 3 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, see . + + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + +/* FAT32, VFAT, Atari format support, and various fixes additions May 1998 + * by Roman Hodek */ + + +#ifndef _DOSFSCK_H +#define _DOSFSCK_H + +#include +#define _LINUX_STAT_H /* hack to avoid inclusion of */ +#define _LINUX_STRING_H_ /* hack to avoid inclusion of */ +#define _LINUX_FS_H /* hack to avoid inclusion of */ + +# include +# include + +#include + +#undef CF_LE_W +#undef CF_LE_L +#undef CT_LE_W +#undef CT_LE_L + +#if defined __arm__ + #undef __BYTE_ORDER + #define __BYTE_ORDER __LITTLE_ENDIAN +#endif + +#if __BYTE_ORDER == __BIG_ENDIAN +#include +#define CF_LE_W(v) bswap_16(v) +#define CF_LE_L(v) bswap_32(v) +#define CT_LE_W(v) CF_LE_W(v) +#define CT_LE_L(v) CF_LE_L(v) +#else +#define CF_LE_W(v) (v) +#define CF_LE_L(v) (v) +#define CT_LE_W(v) (v) +#define CT_LE_L(v) (v) +#endif /* __BIG_ENDIAN */ + +#define VFAT_LN_ATTR (ATTR_RO | ATTR_HIDDEN | ATTR_SYS | ATTR_VOLUME) + +/* ++roman: Use own definition of boot sector structure -- the kernel headers' + * name for it is msdos_boot_sector in 2.0 and fat_boot_sector in 2.1 ... */ +struct boot_sector { + __u8 ignored[3]; /* Boot strap short or near jump */ + __u8 system_id[8]; /* Name - can be used to special case + partition manager volumes */ + __u8 sector_size[2]; /* bytes per logical sector */ + __u8 cluster_size; /* sectors/cluster */ + __u16 reserved; /* reserved sectors */ + __u8 fats; /* number of FATs */ + __u8 dir_entries[2]; /* root directory entries */ + __u8 sectors[2]; /* number of sectors */ + __u8 media; /* media code (unused) */ + __u16 fat_length; /* sectors/FAT */ + __u16 secs_track; /* sectors per track */ + __u16 heads; /* number of heads */ + __u32 hidden; /* hidden sectors (unused) */ + __u32 total_sect; /* number of sectors (if sectors == 0) */ + + /* The following fields are only used by FAT32 */ + __u32 fat32_length; /* sectors/FAT */ + __u16 flags; /* bit 8: fat mirroring, low 4: active fat */ + __u8 version[2]; /* major, minor filesystem version */ + __u32 root_cluster; /* first cluster in root directory */ + __u16 info_sector; /* filesystem info sector */ + __u16 backup_boot; /* backup boot sector */ + __u8 reserved2[12]; /* Unused */ + + __u8 drive_number; /* Logical Drive Number */ + __u8 reserved3; /* Unused */ + + __u8 extended_sig; /* Extended Signature (0x29) */ + __u32 serial; /* Serial number */ + __u8 label[11]; /* FS label */ + __u8 fs_type[8]; /* FS Type */ + + /* fill up to 512 bytes */ + __u8 junk[422]; +} __attribute__ ((packed)); + +struct boot_sector_16 { + __u8 ignored[3]; /* Boot strap short or near jump */ + __u8 system_id[8]; /* Name - can be used to special case + partition manager volumes */ + __u8 sector_size[2]; /* bytes per logical sector */ + __u8 cluster_size; /* sectors/cluster */ + __u16 reserved; /* reserved sectors */ + __u8 fats; /* number of FATs */ + __u8 dir_entries[2]; /* root directory entries */ + __u8 sectors[2]; /* number of sectors */ + __u8 media; /* media code (unused) */ + __u16 fat_length; /* sectors/FAT */ + __u16 secs_track; /* sectors per track */ + __u16 heads; /* number of heads */ + __u32 hidden; /* hidden sectors (unused) */ + __u32 total_sect; /* number of sectors (if sectors == 0) */ + + __u8 drive_number; /* Logical Drive Number */ + __u8 reserved2; /* Unused */ + + __u8 extended_sig; /* Extended Signature (0x29) */ + __u32 serial; /* Serial number */ + __u8 label[11]; /* FS label */ + __u8 fs_type[8]; /* FS Type */ + + /* fill up to 512 bytes */ + __u8 junk[450]; +} __attribute__ ((packed)); + +struct info_sector { + __u32 magic; /* Magic for info sector ('RRaA') */ + __u8 junk[0x1dc]; + __u32 reserved1; /* Nothing as far as I can tell */ + __u32 signature; /* 0x61417272 ('rrAa') */ + __u32 free_clusters; /* Free cluster count. -1 if unknown */ + __u32 next_cluster; /* Most recently allocated cluster. */ + __u32 reserved2[3]; + __u16 reserved3; + __u16 boot_sign; +}; + +typedef struct { + __u8 name[8],ext[3]; /* name and extension */ + __u8 attr; /* attribute bits */ + __u8 lcase; /* Case for base and extension */ + __u8 ctime_ms; /* Creation time, milliseconds */ + __u16 ctime; /* Creation time */ + __u16 cdate; /* Creation date */ + __u16 adate; /* Last access date */ + __u16 starthi; /* High 16 bits of cluster in FAT32 */ + __u16 time,date,start;/* time, date and first cluster */ + __u32 size; /* file size (in bytes) */ +} DIR_ENT; + +typedef struct _dos_file { + DIR_ENT dir_ent; + char *lfn; + loff_t offset; + struct _dos_file *parent; /* parent directory */ + struct _dos_file *next; /* next entry */ + struct _dos_file *first; /* first entry (directory only) */ +} DOS_FILE; + +typedef struct { + unsigned long value; + unsigned long reserved; + DOS_FILE *owner; + int prev; /* number of previous clusters */ +} FAT_ENTRY; + +typedef struct { + int nfats; + loff_t fat_start; + unsigned int fat_size; /* unit is bytes */ + unsigned int fat_bits; /* size of a FAT entry */ + unsigned int eff_fat_bits; /* # of used bits in a FAT entry */ + unsigned long root_cluster; /* 0 for old-style root dir */ + loff_t root_start; + unsigned int root_entries; + loff_t data_start; + unsigned int cluster_size; + unsigned long clusters; + loff_t fsinfo_start; /* 0 if not present */ + long free_clusters; + loff_t backupboot_start; /* 0 if not present */ + FAT_ENTRY *fat; + char *label; +} DOS_FS; + +#ifndef offsetof +#define offsetof(t,e) ((int)&(((t *)0)->e)) +#endif + +extern int interactive,list,verbose,test,write_immed; +extern int atari_format; +extern unsigned n_files; +extern void *mem_queue; + +/* value to use as end-of-file marker */ +#define FAT_EOF(fs) ((atari_format ? 0xfff : 0xff8) | FAT_EXTD(fs)) +#define FAT_IS_EOF(fs,v) ((unsigned long)(v) >= (0xff8|FAT_EXTD(fs))) +/* value to mark bad clusters */ +#define FAT_BAD(fs) (0xff7 | FAT_EXTD(fs)) +/* range of values used for bad clusters */ +#define FAT_MIN_BAD(fs) ((atari_format ? 0xff0 : 0xff7) | FAT_EXTD(fs)) +#define FAT_MAX_BAD(fs) ((atari_format ? 0xff7 : 0xff7) | FAT_EXTD(fs)) +#define FAT_IS_BAD(fs,v) ((v) >= FAT_MIN_BAD(fs) && (v) <= FAT_MAX_BAD(fs)) + +/* return -16 as a number with fs->fat_bits bits */ +#define FAT_EXTD(fs) (((1 << fs->eff_fat_bits)-1) & ~0xf) + +#endif + +/* Local Variables: */ +/* tab-width: 8 */ +/* End: */ diff --git a/src/dosfslabel.c b/src/dosfslabel.c new file mode 100644 index 0000000..e7be1f6 --- /dev/null +++ b/src/dosfslabel.c @@ -0,0 +1,126 @@ +/* dosfslabel.c - User interface + + Copyright (C) 1993 Werner Almesberger + Copyright (C) 1998 Roman Hodek + Copyright (C) 2007 Red Hat, Inc. + + 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 3 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, see . + + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + +#include "version.h" + +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "dosfsck.h" +#include "io.h" +#include "boot.h" +#include "fat.h" +#include "file.h" +#include "check.h" + + +int interactive = 0,list = 0,test = 0,verbose = 0,write_immed = 0; +int atari_format = 0; +unsigned n_files = 0; +void *mem_queue = NULL; + + +static void usage(int error) +{ + FILE *f = error ? stderr : stdout; + int status = error ? 1 : 0; + + fprintf(f,"usage: dosfslabel device [label]\n"); + exit(status); +} + +/* + * ++roman: On m68k, check if this is an Atari; if yes, turn on Atari variant + * of MS-DOS filesystem by default. + */ +static void check_atari( void ) +{ +#ifdef __mc68000__ + FILE *f; + char line[128], *p; + + if (!(f = fopen( "/proc/hardware", "r" ))) { + perror( "/proc/hardware" ); + return; + } + + while( fgets( line, sizeof(line), f ) ) { + if (strncmp( line, "Model:", 6 ) == 0) { + p = line + 6; + p += strspn( p, " \t" ); + if (strncmp( p, "Atari ", 6 ) == 0) + atari_format = 1; + break; + } + } + fclose( f ); +#endif +} + + +int main(int argc, char *argv[]) +{ + DOS_FS fs; + int rw = 0; + + char *device = NULL; + char *label = NULL; + + check_atari(); + + if (argc < 2 || argc > 3) + usage(1); + + if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) + usage(0); + else if (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version")) { + printf( "dosfslabel " VERSION ", " VERSION_DATE ", FAT32, LFN\n" ); + exit(0); + } + + device = argv[1]; + if (argc == 3) { + label = argv[2]; + if (strlen(label) > 11) { + fprintf(stderr, + "dosfslabel: labels can be no longer than 11 characters\n"); + exit(1); + } + rw = 1; + } + + fs_open(device, rw); + read_boot(&fs); + if (!rw) { + fprintf(stdout, "%s\n", fs.label); + exit(0); + } + + write_label(&fs, label); + return fs_close(rw) ? 1 : 0; +} diff --git a/src/fat.c b/src/fat.c new file mode 100644 index 0000000..d09d888 --- /dev/null +++ b/src/fat.c @@ -0,0 +1,381 @@ +/* fat.c - Read/write access to the FAT + + Copyright (C) 1993 Werner Almesberger + Copyright (C) 1998 Roman Hodek + + 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 3 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, see . + + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + +/* FAT32, VFAT, Atari format support, and various fixes additions May 1998 + * by Roman Hodek */ + + +#include +#include +#include +#include + +#include "common.h" +#include "dosfsck.h" +#include "io.h" +#include "check.h" +#include "fat.h" + + +static void get_fat(FAT_ENTRY *entry,void *fat,unsigned long cluster,DOS_FS *fs) +{ + unsigned char *ptr; + + switch(fs->fat_bits) { + case 12: + ptr = &((unsigned char *) fat)[cluster*3/2]; + entry->value = 0xfff & (cluster & 1 ? (ptr[0] >> 4) | (ptr[1] << 4) : + (ptr[0] | ptr[1] << 8)); + break; + case 16: + entry->value = CF_LE_W(((unsigned short *) fat)[cluster]); + break; + case 32: + /* According to M$, the high 4 bits of a FAT32 entry are reserved and + * are not part of the cluster number. So we cut them off. */ + { + unsigned long e = CF_LE_L(((unsigned int *) fat)[cluster]); + entry->value = e & 0xfffffff; + entry->reserved = e >> 28; + } + break; + default: + die("Bad FAT entry size: %d bits.",fs->fat_bits); + } + entry->owner = NULL; +} + + +void read_fat(DOS_FS *fs) +{ + int eff_size; + unsigned long i; + void *first,*second = NULL; + int first_ok,second_ok; + + eff_size = ((fs->clusters+2ULL)*fs->fat_bits+7)/8ULL; + first = alloc(eff_size); + fs_read(fs->fat_start,eff_size,first); + if (fs->nfats > 1) { + second = alloc(eff_size); + fs_read(fs->fat_start+fs->fat_size,eff_size,second); + } + if (second && memcmp(first,second,eff_size) != 0) { + FAT_ENTRY first_media, second_media; + get_fat(&first_media,first,0,fs); + get_fat(&second_media,second,0,fs); + first_ok = (first_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs); + second_ok = (second_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs); + if (first_ok && !second_ok) { + printf("FATs differ - using first FAT.\n"); + fs_write(fs->fat_start+fs->fat_size,eff_size,first); + } + if (!first_ok && second_ok) { + printf("FATs differ - using second FAT.\n"); + fs_write(fs->fat_start,eff_size,second); + memcpy(first,second,eff_size); + } + if (first_ok && second_ok) { + if (interactive) { + printf("FATs differ but appear to be intact. Use which FAT ?\n" + "1) Use first FAT\n2) Use second FAT\n"); + if (get_key("12","?") == '1') { + fs_write(fs->fat_start+fs->fat_size,eff_size,first); + } else { + fs_write(fs->fat_start,eff_size,second); + memcpy(first,second,eff_size); + } + } + else { + printf("FATs differ but appear to be intact. Using first " + "FAT.\n"); + fs_write(fs->fat_start+fs->fat_size,eff_size,first); + } + } + if (!first_ok && !second_ok) { + printf("Both FATs appear to be corrupt. Giving up.\n"); + exit(1); + } + } + if (second) { + free(second); + } + fs->fat = qalloc(&mem_queue,sizeof(FAT_ENTRY)*(fs->clusters+2ULL)); + for (i = 2; i < fs->clusters+2; i++) get_fat(&fs->fat[i],first,i,fs); + for (i = 2; i < fs->clusters+2; i++) + if (fs->fat[i].value >= fs->clusters+2 && + (fs->fat[i].value < FAT_MIN_BAD(fs))) { + printf("Cluster %ld out of range (%ld > %ld). Setting to EOF.\n", + i-2,fs->fat[i].value,fs->clusters+2-1); + set_fat(fs,i,-1); + } + free(first); +} + + +void set_fat(DOS_FS *fs,unsigned long cluster,unsigned long new) +{ + unsigned char data[4]; + int size; + loff_t offs; + + if ((long)new == -1) + new = FAT_EOF(fs); + else if ((long)new == -2) + new = FAT_BAD(fs); + switch( fs->fat_bits ) { + case 12: + offs = fs->fat_start+cluster*3/2; + if (cluster & 1) { + data[0] = ((new & 0xf) << 4) | (fs->fat[cluster-1].value >> 8); + data[1] = new >> 4; + } + else { + data[0] = new & 0xff; + data[1] = (new >> 8) | (cluster == fs->clusters-1 ? 0 : + (0xff & fs->fat[cluster+1].value) << 4); + } + size = 2; + break; + case 16: + offs = fs->fat_start+cluster*2; + *(unsigned short *) data = CT_LE_W(new); + size = 2; + break; + case 32: + offs = fs->fat_start+cluster*4; + /* According to M$, the high 4 bits of a FAT32 entry are reserved and + * are not part of the cluster number. So we never touch them. */ + *(unsigned long *) data = CT_LE_L( (new & 0xfffffff) | + (fs->fat[cluster].reserved << 28) ); + size = 4; + break; + default: + die("Bad FAT entry size: %d bits.",fs->fat_bits); + } + fs->fat[cluster].value = new; + fs_write(offs,size,&data); + fs_write(offs+fs->fat_size,size,&data); +} + + +int bad_cluster(DOS_FS *fs,unsigned long cluster) +{ + return FAT_IS_BAD(fs,fs->fat[cluster].value); +} + + +unsigned long next_cluster(DOS_FS *fs,unsigned long cluster) +{ + unsigned long value; + + value = fs->fat[cluster].value; + if (FAT_IS_BAD(fs,value)) + die("Internal error: next_cluster on bad cluster"); + return FAT_IS_EOF(fs,value) ? -1 : value; +} + + +loff_t cluster_start(DOS_FS *fs,unsigned long cluster) +{ + return fs->data_start+((loff_t)cluster-2)*(unsigned long long)fs->cluster_size; +} + + +void set_owner(DOS_FS *fs,unsigned long cluster,DOS_FILE *owner) +{ + if (owner && fs->fat[cluster].owner) + die("Internal error: attempt to change file owner"); + fs->fat[cluster].owner = owner; +} + + +DOS_FILE *get_owner(DOS_FS *fs,unsigned long cluster) +{ + return fs->fat[cluster].owner; +} + + +void fix_bad(DOS_FS *fs) +{ + unsigned long i; + + if (verbose) + printf("Checking for bad clusters.\n"); + for (i = 2; i < fs->clusters+2; i++) + if (!get_owner(fs,i) && !FAT_IS_BAD(fs,fs->fat[i].value)) + if (!fs_test(cluster_start(fs,i),fs->cluster_size)) { + printf("Cluster %lu is unreadable.\n",i); + set_fat(fs,i,-2); + } +} + + +void reclaim_free(DOS_FS *fs) +{ + int reclaimed; + unsigned long i; + + if (verbose) + printf("Checking for unused clusters.\n"); + reclaimed = 0; + for (i = 2; i < fs->clusters+2; i++) + if (!get_owner(fs,i) && fs->fat[i].value && + !FAT_IS_BAD(fs,fs->fat[i].value)) { + set_fat(fs,i,0); + reclaimed++; + } + if (reclaimed) + printf("Reclaimed %d unused cluster%s (%llu bytes).\n",reclaimed, + reclaimed == 1 ? "" : "s",(unsigned long long)reclaimed*fs->cluster_size); +} + + +static void tag_free(DOS_FS *fs,DOS_FILE *ptr) +{ + DOS_FILE *owner; + int prev; + unsigned long i,walk; + + for (i = 2; i < fs->clusters+2; i++) + if (fs->fat[i].value && !FAT_IS_BAD(fs,fs->fat[i].value) && + !get_owner(fs,i) && !fs->fat[i].prev) { + prev = 0; + for (walk = i; walk > 0 && walk != -1; + walk = next_cluster(fs,walk)) { + if (!(owner = get_owner(fs,walk))) set_owner(fs,walk,ptr); + else if (owner != ptr) + die("Internal error: free chain collides with file"); + else { + set_fat(fs,prev,-1); + break; + } + prev = walk; + } + } +} + + +void reclaim_file(DOS_FS *fs) +{ + DOS_FILE dummy; + int reclaimed,files,changed; + unsigned long i,next,walk; + + if (verbose) + printf("Reclaiming unconnected clusters.\n"); + for (i = 2; i < fs->clusters+2; i++) fs->fat[i].prev = 0; + for (i = 2; i < fs->clusters+2; i++) { + next = fs->fat[i].value; + if (!get_owner(fs,i) && next && next < fs->clusters+2) { + if (get_owner(fs,next) || !fs->fat[next].value || + FAT_IS_BAD(fs,fs->fat[next].value)) set_fat(fs,i,-1); + else fs->fat[next].prev++; + } + } + do { + tag_free(fs,&dummy); + changed = 0; + for (i = 2; i < fs->clusters+2; i++) + if (fs->fat[i].value && !FAT_IS_BAD(fs,fs->fat[i].value) && + !get_owner(fs, i)) { + if (!fs->fat[fs->fat[i].value].prev--) + die("Internal error: prev going below zero"); + set_fat(fs,i,-1); + changed = 1; + printf("Broke cycle at cluster %lu in free chain.\n",i); + break; + } + } + while (changed); + files = reclaimed = 0; + for (i = 2; i < fs->clusters+2; i++) + if (get_owner(fs,i) == &dummy && !fs->fat[i].prev) { + DIR_ENT de; + loff_t offset; + files++; + offset = alloc_rootdir_entry(fs,&de,"FSCK%04dREC"); + de.start = CT_LE_W(i&0xffff); + if (fs->fat_bits == 32) + de.starthi = CT_LE_W(i>>16); + for (walk = i; walk > 0 && walk != -1; + walk = next_cluster(fs,walk)) { + de.size = CT_LE_L(CF_LE_L(de.size)+fs->cluster_size); + reclaimed++; + } + fs_write(offset,sizeof(DIR_ENT),&de); + } + if (reclaimed) + printf("Reclaimed %d unused cluster%s (%llu bytes) in %d chain%s.\n", + reclaimed,reclaimed == 1 ? "" : "s",(unsigned long long)reclaimed*fs->cluster_size,files, + files == 1 ? "" : "s"); +} + + +unsigned long update_free(DOS_FS *fs) +{ + unsigned long i; + unsigned long free = 0; + int do_set = 0; + + for (i = 2; i < fs->clusters+2; i++) + if (!get_owner(fs,i) && !FAT_IS_BAD(fs,fs->fat[i].value)) + ++free; + + if (!fs->fsinfo_start) + return free; + + if (verbose) + printf("Checking free cluster summary.\n"); + if (fs->free_clusters >= 0) { + if (free != fs->free_clusters) { + printf( "Free cluster summary wrong (%ld vs. really %ld)\n", + fs->free_clusters,free); + if (interactive) + printf( "1) Correct\n2) Don't correct\n" ); + else printf( " Auto-correcting.\n" ); + if (!interactive || get_key("12","?") == '1') + do_set = 1; + } + } + else { + printf( "Free cluster summary uninitialized (should be %ld)\n", free ); + if (interactive) + printf( "1) Set it\n2) Leave it uninitialized\n" ); + else printf( " Auto-setting.\n" ); + if (!interactive || get_key("12","?") == '1') + do_set = 1; + } + + if (do_set) { + fs->free_clusters = free; + free = CT_LE_L(free); + fs_write(fs->fsinfo_start+offsetof(struct info_sector,free_clusters), + sizeof(free),&free); + } + + return free; +} + +/* Local Variables: */ +/* tab-width: 8 */ +/* End: */ diff --git a/src/fat.h b/src/fat.h new file mode 100644 index 0000000..c5f7849 --- /dev/null +++ b/src/fat.h @@ -0,0 +1,81 @@ +/* fat.h - Read/write access to the FAT + + Copyright (C) 1993 Werner Almesberger + + 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 3 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, see . + + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + + +#ifndef _FAT_H +#define _FAT_H + +void read_fat(DOS_FS *fs); + +/* Loads the FAT of the file system described by FS. Initializes the FAT, + replaces broken FATs and rejects invalid cluster entries. */ + +void set_fat(DOS_FS *fs,unsigned long cluster,unsigned long new); + +/* Changes the value of the CLUSTERth cluster of the FAT of FS to NEW. Special + values of NEW are -1 (EOF, 0xff8 or 0xfff8) and -2 (bad sector, 0xff7 or + 0xfff7) */ + +int bad_cluster(DOS_FS *fs,unsigned long cluster); + +/* Returns a non-zero integer if the CLUSTERth cluster is marked as bad or zero + otherwise. */ + +unsigned long next_cluster(DOS_FS *fs,unsigned long cluster); + +/* Returns the number of the cluster following CLUSTER, or -1 if this is the + last cluster of the respective cluster chain. CLUSTER must not be a bad + cluster. */ + +loff_t cluster_start(DOS_FS *fs,unsigned long cluster); + +/* Returns the byte offset of CLUSTER, relative to the respective device. */ + +void set_owner(DOS_FS *fs,unsigned long cluster,DOS_FILE *owner); + +/* Sets the owner pointer of the respective cluster to OWNER. If OWNER was NULL + before, it can be set to NULL or any non-NULL value. Otherwise, only NULL is + accepted as the new value. */ + +DOS_FILE *get_owner(DOS_FS *fs,unsigned long cluster); + +/* Returns the owner of the repective cluster or NULL if the cluster has no + owner. */ + +void fix_bad(DOS_FS *fs); + +/* Scans the disk for currently unused bad clusters and marks them as bad. */ + +void reclaim_free(DOS_FS *fs); + +/* Marks all allocated, but unused clusters as free. */ + +void reclaim_file(DOS_FS *fs); + +/* Scans the FAT for chains of allocated, but unused clusters and creates files + for them in the root directory. Also tries to fix all inconsistencies (e.g. + loops, shared clusters, etc.) in the process. */ + +unsigned long update_free(DOS_FS *fs); + +/* Updates free cluster count in FSINFO sector. */ + +#endif diff --git a/src/file.c b/src/file.c new file mode 100644 index 0000000..c389c60 --- /dev/null +++ b/src/file.c @@ -0,0 +1,263 @@ +/* file.c - Additional file attributes + + Copyright (C) 1993 Werner Almesberger + Copyright (C) 1998 Roman Hodek + + 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 3 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, see . + + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + +/* FAT32, VFAT, Atari format support, and various fixes additions May 1998 + * by Roman Hodek */ + + +#include +#include +#include +#include +#include + +#define _LINUX_STAT_H /* hack to avoid inclusion of */ +#define _LINUX_STRING_H_ /* hack to avoid inclusion of */ +#define _LINUX_FS_H /* hack to avoid inclusion of */ + +# include + +#include + +#include "common.h" +#include "file.h" + + +FDSC *fp_root = NULL; + + +static void put_char(char **p,unsigned char c) +{ + if ((c >= ' ' && c < 0x7f) || c >= 0xa0) *(*p)++ = c; + else { + *(*p)++ = '\\'; + *(*p)++ = '0'+(c >> 6); + *(*p)++ = '0'+((c >> 3) & 7); + *(*p)++ = '0'+(c & 7); + } +} + + +char *file_name(unsigned char *fixed) +{ + static char path[MSDOS_NAME*4+2]; + char *p; + int i,j; + + p = path; + for (i = j = 0; i < 8; i++) + if (fixed[i] != ' ') { + while (j++ < i) *p++ = ' '; + put_char(&p,fixed[i]); + } + if (strncmp(fixed+8," ",3)) { + *p++ = '.'; + for (i = j = 0; i < 3; i++) + if (fixed[i+8] != ' ') { + while (j++ < i) *p++ = ' '; + put_char(&p,fixed[i+8]); + } + } + *p = 0; + return path; +} + + +int file_cvt(unsigned char *name,unsigned char *fixed) +{ + unsigned char c; + int size,ext,cnt; + + size = 8; + ext = 0; + while (*name) { + c = *name; + if (c < ' ' || c > 0x7e || strchr("*?<>|\"/",c)) { + printf("Invalid character in name. Use \\ooo for special " + "characters.\n"); + return 0; + } + if (c == '.') { + if (ext) { + printf("Duplicate dots in name.\n"); + return 0; + } + while (size--) *fixed++ = ' '; + size = 3; + ext = 1; + name++; + continue; + } + if (c == '\\') { + c = 0; + for (cnt = 3; cnt; cnt--) { + if (*name < '0' || *name > '7') { + printf("Invalid octal character.\n"); + return 0; + } + c = c*8+*name++-'0'; + } + if (cnt < 4) { + printf("Expected three octal digits.\n"); + return 0; + } + name += 3; + } + if (islower(c)) c = toupper(c); + if (size) { + *fixed++ = c; + size--; + } + name++; + } + if (*name || size == 8) return 0; + if (!ext) { + while (size--) *fixed++ = ' '; + size = 3; + } + while (size--) *fixed++ = ' '; + return 1; +} + + +void file_add(char *path,FD_TYPE type) +{ + FDSC **current,*walk; + char name[MSDOS_NAME]; + char *here; + + current = &fp_root; + if (*path != '/') die("%s: Absolute path required.",path); + path++; + while (1) { + if ((here = strchr(path,'/'))) *here = 0; + if (!file_cvt(path,name)) exit(2); + for (walk = *current; walk; walk = walk->next) + if (!here && (!strncmp(name,walk->name,MSDOS_NAME) || (type == + fdt_undelete && !strncmp(name+1,walk->name+1,MSDOS_NAME-1)))) + die("Ambiguous name: \"%s\"",path); + else if (here && !strncmp(name,walk->name,MSDOS_NAME)) break; + if (!walk) { + walk = alloc(sizeof(FDSC)); + strncpy(walk->name,name,MSDOS_NAME); + walk->type = here ? fdt_none : type; + walk->first = NULL; + walk->next = *current; + *current = walk; + } + current = &walk->first; + if (!here) break; + *here = '/'; + path = here+1; + } +} + + +FDSC **file_cd(FDSC **curr,char *fixed) +{ + FDSC **walk; + + if (!curr || !*curr) return NULL; + for (walk = curr; *walk; walk = &(*walk)->next) + if (!strncmp((*walk)->name,fixed,MSDOS_NAME) && (*walk)->first) + return &(*walk)->first; + return NULL; +} + + +static FDSC **file_find(FDSC **dir,char *fixed) +{ + if (!dir || !*dir) return NULL; + if (*(unsigned char *) fixed == DELETED_FLAG) { + while (*dir) { + if (!strncmp((*dir)->name+1,fixed+1,MSDOS_NAME-1) && !(*dir)->first) + return dir; + dir = &(*dir)->next; + } + return NULL; + } + while (*dir) { + if (!strncmp((*dir)->name,fixed,MSDOS_NAME) && !(*dir)->first) + return dir; + dir = &(*dir)->next; + } + return NULL; +} + + +FD_TYPE file_type(FDSC **curr,char *fixed) +{ + FDSC **this; + + if ((this = file_find(curr,fixed))) return (*this)->type; + return fdt_none; +} + + +void file_modify(FDSC **curr,char *fixed) +{ + FDSC **this,*next; + + if (!(this = file_find(curr,fixed))) + die("Internal error: file_find failed"); + switch ((*this)->type) { + case fdt_drop: + printf("Dropping %s\n",file_name(fixed)); + *(unsigned char *) fixed = DELETED_FLAG; + break; + case fdt_undelete: + *fixed = *(*this)->name; + printf("Undeleting %s\n",file_name(fixed)); + break; + default: + die("Internal error: file_modify"); + } + next = (*this)->next; + free(*this); + *this = next; +} + + +static void report_unused(FDSC *this) +{ + FDSC *next; + + while (this) { + next = this->next; + if (this->first) report_unused(this->first); + else if (this->type != fdt_none) + printf("Warning: did not %s file %s\n",this->type == fdt_drop ? + "drop" : "undelete",file_name(this->name)); + free(this); + this = next; + } +} + + +void file_unused(void) +{ + report_unused(fp_root); +} + +/* Local Variables: */ +/* tab-width: 8 */ +/* End: */ diff --git a/src/file.h b/src/file.h new file mode 100644 index 0000000..b38523b --- /dev/null +++ b/src/file.h @@ -0,0 +1,72 @@ +/* file.h - Additional file attributes + + Copyright (C) 1993 Werner Almesberger + + 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 3 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, see . + + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + + +#ifndef _FILE_H +#define _FILE_H + +typedef enum { fdt_none,fdt_drop,fdt_undelete } FD_TYPE; + +typedef struct _fptr { + char name[MSDOS_NAME]; + FD_TYPE type; + struct _fptr *first; /* first entry */ + struct _fptr *next; /* next file in directory */ +} FDSC; + + +extern FDSC *fp_root; + + +char *file_name(unsigned char *fixed); + +/* Returns a pointer to a pretty-printed representation of a fixed MS-DOS file + name. */ + +int file_cvt(unsigned char *name,unsigned char *fixed); + +/* Converts a pretty-printed file name to the fixed MS-DOS format. Returns a + non-zero integer on success, zero on failure. */ + +void file_add(char *path,FD_TYPE type); + +/* Define special attributes for a path. TYPE can be either FDT_DROP or + FDT_UNDELETE. */ + +FDSC **file_cd(FDSC **curr,char *fixed); + +/* Returns a pointer to the directory descriptor of the subdirectory FIXED of + CURR, or NULL if no such subdirectory exists. */ + +FD_TYPE file_type(FDSC **curr,char *fixed); + +/* Returns the attribute of the file FIXED in directory CURR or FDT_NONE if no + such file exists or if CURR is NULL. */ + +void file_modify(FDSC **curr,char *fixed); + +/* Performs the necessary operation on the entry of CURR that is named FIXED. */ + +void file_unused(void); + +/* Displays warnings for all unused file attributes. */ + +#endif diff --git a/src/io.c b/src/io.c new file mode 100644 index 0000000..0ab0bbf --- /dev/null +++ b/src/io.c @@ -0,0 +1,209 @@ +/* io.c - Virtual disk input/output + + Copyright (C) 1993 Werner Almesberger + Copyright (C) 1998 Roman Hodek + + 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 3 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, see . + + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + +/* + * Thu Feb 26 01:15:36 CET 1998: Martin Schulze + * Fixed nasty bug that caused every file with a name like + * xxxxxxxx.xxx to be treated as bad name that needed to be fixed. + */ + +/* FAT32, VFAT, Atari format support, and various fixes additions May 1998 + * by Roman Hodek */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dosfsck.h" +#include "common.h" +#include "io.h" + + +typedef struct _change { + void *data; + loff_t pos; + int size; + struct _change *next; +} CHANGE; + + +static CHANGE *changes,*last; +static int fd,did_change = 0; + +unsigned device_no; + + +#ifdef __DJGPP__ +#include "volume.h" /* DOS lowlevel disk access functions */ +#undef llseek +static loff_t llseek( int fd, loff_t offset, int whence ) +{ + if ((whence != SEEK_SET) || (fd == 4711)) return -1; /* only those supported */ + return VolumeSeek(offset); +} +#define open OpenVolume +#define close CloseVolume +#define read(a,b,c) ReadVolume(b,c) +#define write(a,b,c) WriteVolume(b,c) +#endif + +void fs_open(char *path,int rw) +{ + struct stat stbuf; + + if ((fd = open(path,rw ? O_RDWR : O_RDONLY)) < 0) + pdie("open %s",path); + changes = last = NULL; + did_change = 0; + +#ifndef _DJGPP_ + if (fstat(fd,&stbuf) < 0) + pdie("fstat %s",path); + device_no = S_ISBLK(stbuf.st_mode) ? (stbuf.st_rdev >> 8) & 0xff : 0; +#else + if (IsWorkingOnImageFile()) { + if (fstat(GetVolumeHandle(),&stbuf) < 0) + pdie("fstat image %s",path); + device_no = 0; + } + else { + /* return 2 for floppy, 1 for ramdisk, 7 for loopback */ + /* used by boot.c in Atari mode: floppy always FAT12, */ + /* loopback / ramdisk only FAT12 if usual floppy size, */ + /* harddisk always FAT16 on Atari... */ + device_no = (GetVolumeHandle() < 2) ? 2 : 1; + /* telling "floppy" for A:/B:, "ramdisk" for the rest */ + } +#endif +} + + +void fs_read(loff_t pos,int size,void *data) +{ + CHANGE *walk; + int got; + + if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos); + if ((got = read(fd,data,size)) < 0) pdie("Read %d bytes at %lld",size,pos); + if (got != size) die("Got %d bytes instead of %d at %lld",got,size,pos); + for (walk = changes; walk; walk = walk->next) { + if (walk->pos < pos+size && walk->pos+walk->size > pos) { + if (walk->pos < pos) + memcpy(data,(char *) walk->data+pos-walk->pos,min(size, + walk->size-pos+walk->pos)); + else memcpy((char *) data+walk->pos-pos,walk->data,min(walk->size, + size+pos-walk->pos)); + } + } +} + + +int fs_test(loff_t pos,int size) +{ + void *scratch; + int okay; + + if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos); + scratch = alloc(size); + okay = read(fd,scratch,size) == size; + free(scratch); + return okay; +} + + +void fs_write(loff_t pos,int size,void *data) +{ + CHANGE *new; + int did; + + if (write_immed) { + did_change = 1; + if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos); + if ((did = write(fd,data,size)) == size) return; + if (did < 0) pdie("Write %d bytes at %lld",size,pos); + die("Wrote %d bytes instead of %d at %lld",did,size,pos); + } + new = alloc(sizeof(CHANGE)); + new->pos = pos; + memcpy(new->data = alloc(new->size = size),data,size); + new->next = NULL; + if (last) last->next = new; + else changes = new; + last = new; +} + + +static void fs_flush(void) +{ + CHANGE *this; + int size; + + while (changes) { + this = changes; + changes = changes->next; + if (llseek(fd,this->pos,0) != this->pos) + fprintf(stderr,"Seek to %lld failed: %s\n Did not write %d bytes.\n", + (long long)this->pos,strerror(errno),this->size); + else if ((size = write(fd,this->data,this->size)) < 0) + fprintf(stderr,"Writing %d bytes at %lld failed: %s\n",this->size, + (long long)this->pos,strerror(errno)); + else if (size != this->size) + fprintf(stderr,"Wrote %d bytes instead of %d bytes at %lld." + "\n",size,this->size,(long long)this->pos); + free(this->data); + free(this); + } +} + + +int fs_close(int write) +{ + CHANGE *next; + int changed; + + changed = !!changes; + if (write) fs_flush(); + else while (changes) { + next = changes->next; + free(changes->data); + free(changes); + changes = next; + } + if (close(fd) < 0) pdie("closing file system"); + return changed || did_change; +} + + +int fs_changed(void) +{ + return !!changes || did_change; +} + +/* Local Variables: */ +/* tab-width: 8 */ +/* End: */ diff --git a/src/io.h b/src/io.h new file mode 100644 index 0000000..ba0c35b --- /dev/null +++ b/src/io.h @@ -0,0 +1,71 @@ +/* io.h - Virtual disk input/output + + Copyright (C) 1993 Werner Almesberger + Copyright (C) 1998 Roman Hodek + + 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 3 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, see . + + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + +/* FAT32, VFAT, Atari format support, and various fixes additions May 1998 + * by Roman Hodek */ + + +#ifndef _IO_H +#define _IO_H + +#include /* for loff_t */ + +/* In earlier versions, an own llseek() was used, but glibc lseek() is + * sufficient (or even better :) for 64 bit offsets in the meantime */ +#define llseek lseek64 + +void fs_open(char *path,int rw); + +/* Opens the file system PATH. If RW is zero, the file system is opened + read-only, otherwise, it is opened read-write. */ + +void fs_read(loff_t pos,int size,void *data); + +/* Reads SIZE bytes starting at POS into DATA. Performs all applicable + changes. */ + +int fs_test(loff_t pos,int size); + +/* Returns a non-zero integer if SIZE bytes starting at POS can be read without + errors. Otherwise, it returns zero. */ + +void fs_write(loff_t pos,int size,void *data); + +/* If write_immed is non-zero, SIZE bytes are written from DATA to the disk, + starting at POS. If write_immed is zero, the change is added to a list in + memory. */ + +int fs_close(int write); + +/* Closes the file system, performs all pending changes if WRITE is non-zero + and removes the list of changes. Returns a non-zero integer if the file + system has been changed since the last fs_open, zero otherwise. */ + +int fs_changed(void); + +/* Determines whether the file system has changed. See fs_close. */ + +extern unsigned device_no; + +/* Major number of device (0 if file) and size (in 512 byte sectors) */ + +#endif diff --git a/src/lfn.c b/src/lfn.c new file mode 100644 index 0000000..b0db160 --- /dev/null +++ b/src/lfn.c @@ -0,0 +1,495 @@ +/* lfn.c - Functions for handling VFAT long filenames + + Copyright (C) 1998 Roman Hodek + + 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 3 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, see . + + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + +#include +#include +#include +#include +#include + +#include "common.h" +#include "io.h" +#include "dosfsck.h" +#include "lfn.h" +#include "file.h" + +typedef struct { + __u8 id; /* sequence number for slot */ + __u8 name0_4[10]; /* first 5 characters in name */ + __u8 attr; /* attribute byte */ + __u8 reserved; /* always 0 */ + __u8 alias_checksum; /* checksum for 8.3 alias */ + __u8 name5_10[12]; /* 6 more characters in name */ + __u16 start; /* starting cluster number, 0 in long slots */ + __u8 name11_12[4]; /* last 2 characters in name */ +} LFN_ENT; + +#define LFN_ID_START 0x40 +#define LFN_ID_SLOTMASK 0x1f + +#define CHARS_PER_LFN 13 + +/* These modul-global vars represent the state of the LFN parser */ +unsigned char *lfn_unicode = NULL; +unsigned char lfn_checksum; +int lfn_slot = -1; +loff_t *lfn_offsets = NULL; +int lfn_parts = 0; + +static unsigned char fat_uni2esc[64] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z', '+', '-' +}; + +/* This defines which unicode chars are directly convertable to ISO-8859-1 */ +#define UNICODE_CONVERTABLE(cl,ch) (ch == 0 && (cl < 0x80 || cl >= 0xa0)) + +/* for maxlen param */ +#define UNTIL_0 INT_MAX + +/* Convert name part in 'lfn' from unicode to ASCII */ +#define CNV_THIS_PART(lfn) \ + ({ \ + char __part_uni[CHARS_PER_LFN*2]; \ + copy_lfn_part( __part_uni, lfn ); \ + cnv_unicode( __part_uni, CHARS_PER_LFN, 0 ); \ + }) + +/* Convert name parts collected so far (from previous slots) from unicode to + * ASCII */ +#define CNV_PARTS_SO_FAR() \ + (cnv_unicode( lfn_unicode+(lfn_slot*CHARS_PER_LFN*2), \ + lfn_parts*CHARS_PER_LFN, 0 )) + +/* This function converts an unicode string to a normal ASCII string, assuming + * ISO-8859-1 charset. Characters not in 8859-1 are converted to the same + * escape notation as used by the kernel, i.e. the uuencode-like ":xxx" */ +static char *cnv_unicode( const unsigned char *uni, int maxlen, int use_q ) +{ + const unsigned char *up; + unsigned char *out, *cp; + int len, val; + + for( len = 0, up = uni; (up-uni)/2 < maxlen && (up[0] || up[1]); up += 2 ){ + if (UNICODE_CONVERTABLE(up[0],up[1])) + ++len; + else + len += 4; + } + cp = out = use_q ? qalloc( &mem_queue, len+1 ) : alloc( len+1 ); + + for( up = uni; (up-uni)/2 < maxlen && (up[0] || up[1]); up += 2 ) { + if (UNICODE_CONVERTABLE(up[0],up[1])) + *cp++ = up[0]; + else { + /* here the same escape notation is used as in the Linux kernel */ + *cp++ = ':'; + val = (up[1] << 8) + up[0]; + cp[2] = fat_uni2esc[val & 0x3f]; + val >>= 6; + cp[1] = fat_uni2esc[val & 0x3f]; + val >>= 6; + cp[0] = fat_uni2esc[val & 0x3f]; + cp += 3; + } + } + *cp = 0; + + return( out ); +} + + +static void copy_lfn_part( char *dst, LFN_ENT *lfn ) +{ + memcpy( dst, lfn->name0_4, 10 ); + memcpy( dst+10, lfn->name5_10, 12 ); + memcpy( dst+22, lfn->name11_12, 4 ); +} + + +static void clear_lfn_slots( int start, int end ) +{ + int i; + LFN_ENT empty; + + /* New dir entry is zeroed except first byte, which is set to 0xe5. + * This is to avoid that some FAT-reading OSes (not Linux! ;) stop reading + * a directory at the first zero entry... + */ + memset( &empty, 0, sizeof(empty) ); + empty.id = DELETED_FLAG; + + for( i = start; i <= end; ++i ) { + fs_write( lfn_offsets[i], sizeof(LFN_ENT), &empty ); + } +} + +void lfn_reset( void ) +{ + if (lfn_unicode) + free( lfn_unicode ); + lfn_unicode = NULL; + if (lfn_offsets) + free( lfn_offsets ); + lfn_offsets = NULL; + lfn_slot = -1; +} + + +/* This function is only called with de->attr == VFAT_LN_ATTR. It stores part + * of the long name. */ +void lfn_add_slot( DIR_ENT *de, loff_t dir_offset ) +{ + LFN_ENT *lfn = (LFN_ENT *)de; + int slot = lfn->id & LFN_ID_SLOTMASK; + unsigned offset; + + if (lfn_slot == 0) lfn_check_orphaned(); + + if (de->attr != VFAT_LN_ATTR) + die("lfn_add_slot called with non-LFN directory entry"); + + if (lfn->id & LFN_ID_START && slot != 0) { + if (lfn_slot != -1) { + int can_clear = 0; + /* There is already a LFN "in progess", so it is an error that a + * new start entry is here. */ + /* Causes: 1) if slot# == expected: start bit set mysteriously, 2) + * old LFN overwritten by new one */ + /* Fixes: 1) delete previous LFN 2) if slot# == expected and + * checksum ok: clear start bit */ + /* XXX: Should delay that until next LFN known (then can better + * display the name) */ + printf( "A new long file name starts within an old one.\n" ); + if (slot == lfn_slot && + lfn->alias_checksum == lfn_checksum) { + char *part1 = CNV_THIS_PART(lfn); + char *part2 = CNV_PARTS_SO_FAR(); + printf( " It could be that the LFN start bit is wrong here\n" + " if \"%s\" seems to match \"%s\".\n", part1, part2 ); + free( part1 ); + free( part2 ); + can_clear = 1; + } + if (interactive) { + printf( "1: Delete previous LFN\n2: Leave it as it is.\n" ); + if (can_clear) + printf( "3: Clear start bit and concatenate LFNs\n" ); + } + else printf( " Not auto-correcting this.\n" ); + if (interactive) { + switch( get_key( can_clear ? "123" : "12", "?" )) { + case '1': + clear_lfn_slots( 0, lfn_parts-1 ); + lfn_reset(); + break; + case '2': + break; + case '3': + lfn->id &= ~LFN_ID_START; + fs_write( dir_offset+offsetof(LFN_ENT,id), + sizeof(lfn->id), &lfn->id ); + break; + } + } + } + lfn_slot = slot; + lfn_checksum = lfn->alias_checksum; + lfn_unicode = alloc( (lfn_slot*CHARS_PER_LFN+1)*2 ); + lfn_offsets = alloc( lfn_slot*sizeof(loff_t) ); + lfn_parts = 0; + } + else if (lfn_slot == -1 && slot != 0) { + /* No LFN in progress, but slot found; start bit missing */ + /* Causes: 1) start bit got lost, 2) Previous slot with start bit got + * lost */ + /* Fixes: 1) delete LFN, 2) set start bit */ + char *part = CNV_THIS_PART(lfn); + printf( "Long filename fragment \"%s\" found outside a LFN " + "sequence.\n (Maybe the start bit is missing on the " + "last fragment)\n", part ); + if (interactive) { + printf( "1: Delete fragment\n2: Leave it as it is.\n" + "3: Set start bit\n" ); + } + else printf( " Not auto-correcting this.\n" ); + switch( interactive ? get_key( "123", "?" ) : '2') { + case '1': + if (!lfn_offsets) + lfn_offsets = alloc( sizeof(loff_t) ); + lfn_offsets[0] = dir_offset; + clear_lfn_slots( 0, 0 ); + lfn_reset(); + return; + case '2': + lfn_reset(); + return; + case '3': + lfn->id |= LFN_ID_START; + fs_write( dir_offset+offsetof(LFN_ENT,id), + sizeof(lfn->id), &lfn->id ); + lfn_slot = slot; + lfn_checksum = lfn->alias_checksum; + lfn_unicode = alloc( (lfn_slot*CHARS_PER_LFN+1)*2 ); + lfn_offsets = alloc( lfn_slot*sizeof(loff_t) ); + lfn_parts = 0; + break; + } + } + else if (slot != lfn_slot) { + /* wrong sequence number */ + /* Causes: 1) seq-no destroyed */ + /* Fixes: 1) delete LFN, 2) fix number (maybe only if following parts + * are ok?, maybe only if checksum is ok?) (Attention: space + * for name was allocated before!) */ + int can_fix = 0; + printf( "Unexpected long filename sequence number " + "(%d vs. expected %d).\n", + slot, lfn_slot ); + if (lfn->alias_checksum == lfn_checksum && lfn_slot > 0) { + char *part1 = CNV_THIS_PART(lfn); + char *part2 = CNV_PARTS_SO_FAR(); + printf( " It could be that just the number is wrong\n" + " if \"%s\" seems to match \"%s\".\n", part1, part2 ); + free( part1 ); + free( part2 ); + can_fix = 1; + } + if (interactive) { + printf( "1: Delete LFN\n2: Leave it as it is (and ignore LFN so far)\n" ); + if (can_fix) + printf( "3: Correct sequence number\n" ); + } + else printf( " Not auto-correcting this.\n" ); + switch( interactive ? get_key( can_fix ? "123" : "12", "?" ) : '2') { + case '1': + if (!lfn_offsets) { + lfn_offsets = alloc( sizeof(loff_t) ); + lfn_parts = 0; + } + lfn_offsets[lfn_parts++] = dir_offset; + clear_lfn_slots( 0, lfn_parts-1 ); + lfn_reset(); + return; + case '2': + lfn_reset(); + return; + case '3': + lfn->id = (lfn->id & ~LFN_ID_SLOTMASK) | lfn_slot; + fs_write( dir_offset+offsetof(LFN_ENT,id), + sizeof(lfn->id), &lfn->id ); + break; + } + } + + if (lfn->alias_checksum != lfn_checksum) { + /* checksum mismatch */ + /* Causes: 1) checksum field here destroyed */ + /* Fixes: 1) delete LFN, 2) fix checksum */ + printf( "Checksum in long filename part wrong " + "(%02x vs. expected %02x).\n", + lfn->alias_checksum, lfn_checksum ); + if (interactive) { + printf( "1: Delete LFN\n2: Leave it as it is.\n" + "3: Correct checksum\n" ); + } + else printf( " Not auto-correcting this.\n" ); + if (interactive) { + switch( get_key( "123", "?" )) { + case '1': + lfn_offsets[lfn_parts++] = dir_offset; + clear_lfn_slots( 0, lfn_parts-1 ); + lfn_reset(); + return; + case '2': + break; + case '3': + lfn->alias_checksum = lfn_checksum; + fs_write( dir_offset+offsetof(LFN_ENT,alias_checksum), + sizeof(lfn->alias_checksum), &lfn->alias_checksum ); + break; + } + } + } + + if (lfn_slot != -1) { + lfn_slot--; + offset = lfn_slot * CHARS_PER_LFN*2; + copy_lfn_part( lfn_unicode+offset, lfn ); + if (lfn->id & LFN_ID_START) + lfn_unicode[offset+26] = lfn_unicode[offset+27] = 0; + lfn_offsets[lfn_parts++] = dir_offset; + } + + if (lfn->reserved != 0) { + printf( "Reserved field in VFAT long filename slot is not 0 " + "(but 0x%02x).\n", lfn->reserved ); + if (interactive) + printf( "1: Fix.\n2: Leave it.\n" ); + else printf( "Auto-setting to 0.\n" ); + if (!interactive || get_key("12","?") == '1') { + lfn->reserved = 0; + fs_write( dir_offset+offsetof(LFN_ENT,reserved), + sizeof(lfn->reserved), &lfn->reserved ); + } + } + if (lfn->start != CT_LE_W(0)) { + printf( "Start cluster field in VFAT long filename slot is not 0 " + "(but 0x%04x).\n", lfn->start ); + if (interactive) + printf( "1: Fix.\n2: Leave it.\n" ); + else printf( "Auto-setting to 0.\n" ); + if (!interactive || get_key("12","?") == '1') { + lfn->start = CT_LE_W(0); + fs_write( dir_offset+offsetof(LFN_ENT,start), + sizeof(lfn->start),&lfn->start ); + } + } +} + + +/* This function is always called when de->attr != VFAT_LN_ATTR is found, to + * retrieve the previously constructed LFN. */ +char *lfn_get( DIR_ENT *de ) +{ + char *lfn; + __u8 sum; + int i; + + if (de->attr == VFAT_LN_ATTR) + die("lfn_get called with LFN directory entry"); + +#if 0 + if (de->lcase) + printf( "lcase=%02x\n",de->lcase ); +#endif + + if (lfn_slot == -1) + /* no long name for this file */ + return NULL; + + if (lfn_slot != 0) { + /* The long name isn't finished yet. */ + /* Causes: 1) LFN slot overwritten by non-VFAT aware tool */ + /* Fixes: 1) delete LFN 2) move overwriting entry to somewhere else + * and let user enter missing part of LFN (hard to do :-() + * 3) renumber entries and truncate name */ + char *long_name = CNV_PARTS_SO_FAR(); + char *short_name = file_name(de->name); + printf( "Unfinished long file name \"%s\".\n" + " (Start may have been overwritten by %s)\n", + long_name, short_name ); + free( long_name ); + if (interactive) { + printf( "1: Delete LFN\n2: Leave it as it is.\n" + "3: Fix numbering (truncates long name and attaches " + "it to short name %s)\n", short_name ); + } + else printf( " Not auto-correcting this.\n" ); + switch( interactive ? get_key( "123", "?" ) : '2') { + case '1': + clear_lfn_slots( 0, lfn_parts-1 ); + lfn_reset(); + return NULL; + case '2': + lfn_reset(); + return NULL; + case '3': + for( i = 0; i < lfn_parts; ++i ) { + __u8 id = (lfn_parts-i) | (i==0 ? LFN_ID_START : 0); + fs_write( lfn_offsets[i]+offsetof(LFN_ENT,id), + sizeof(id), &id ); + } + memmove( lfn_unicode, lfn_unicode+lfn_slot*CHARS_PER_LFN*2, + lfn_parts*CHARS_PER_LFN*2 ); + break; + } + } + + for (sum = 0, i = 0; i < 11; i++) + sum = (((sum&1) << 7) | ((sum&0xfe) >> 1)) + de->name[i]; + if (sum != lfn_checksum) { + /* checksum doesn't match, long name doesn't apply to this alias */ + /* Causes: 1) alias renamed */ + /* Fixes: 1) Fix checksum in LFN entries */ + char *long_name = CNV_PARTS_SO_FAR(); + char *short_name = file_name(de->name); + printf( "Wrong checksum for long file name \"%s\".\n" + " (Short name %s may have changed without updating the long name)\n", + long_name, short_name ); + free( long_name ); + if (interactive) { + printf( "1: Delete LFN\n2: Leave it as it is.\n" + "3: Fix checksum (attaches to short name %s)\n", + short_name ); + } + else printf( " Not auto-correcting this.\n" ); + if (interactive) { + switch( get_key( "123", "?" )) { + case '1': + clear_lfn_slots( 0, lfn_parts-1 ); + lfn_reset(); + return NULL; + case '2': + lfn_reset(); + return NULL; + case '3': + for( i = 0; i < lfn_parts; ++i ) { + fs_write( lfn_offsets[i]+offsetof(LFN_ENT,alias_checksum), + sizeof(sum), &sum ); + } + break; + } + } + } + + lfn = cnv_unicode( lfn_unicode, UNTIL_0, 1 ); + lfn_reset(); + return( lfn ); +} + +void lfn_check_orphaned(void) +{ + char *long_name; + + if (lfn_slot == -1) + return; + + long_name = CNV_PARTS_SO_FAR(); + printf("Orphaned long file name part \"%s\"\n", long_name); + if (interactive) + printf( "1: Delete.\n2: Leave it.\n" ); + else printf( " Auto-deleting.\n" ); + if (!interactive || get_key("12","?") == '1') { + clear_lfn_slots(0, lfn_parts - 1); + } + lfn_reset(); +} + +/* Local Variables: */ +/* tab-width: 8 */ +/* End: */ diff --git a/src/lfn.h b/src/lfn.h new file mode 100644 index 0000000..8e8f5a1 --- /dev/null +++ b/src/lfn.h @@ -0,0 +1,36 @@ +/* lfn.h - Functions for handling VFAT long filenames + + Copyright (C) 1998 Roman Hodek + + 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 3 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, see . + + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + +#ifndef _LFN_H +#define _LFN_H + +void lfn_reset( void ); +/* Reset the state of the LFN parser. */ + +void lfn_add_slot( DIR_ENT *de, loff_t dir_offset ); +/* Process a dir slot that is a VFAT LFN entry. */ + +char *lfn_get( DIR_ENT *de ); +/* Retrieve the long name for the proper dir entry. */ + +void lfn_check_orphaned(void); + +#endif diff --git a/src/mkdosfs.c b/src/mkdosfs.c new file mode 100644 index 0000000..1264efd --- /dev/null +++ b/src/mkdosfs.c @@ -0,0 +1,1761 @@ +/* mkdosfs.c - utility to create FAT/MS-DOS filesystems + + Copyright (C) 1991 Linus Torvalds + Copyright (C) 1992-1993 Remy Card + Copyright (C) 1993-1994 David Hudson + Copyright (C) 1998 H. Peter Anvin + Copyright (C) 1998-2005 Roman Hodek + + 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 3 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, see . + + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + +/* Description: Utility to allow an MS-DOS filesystem to be created + under Linux. A lot of the basic structure of this program has been + borrowed from Remy Card's "mke2fs" code. + + As far as possible the aim here is to make the "mkdosfs" command + look almost identical to the other Linux filesystem make utilties, + eg bad blocks are still specified as blocks, not sectors, but when + it comes down to it, DOS is tied to the idea of a sector (512 bytes + as a rule), and not the block. For example the boot block does not + occupy a full cluster. + + Fixes/additions May 1998 by Roman Hodek + : + - Atari format support + - New options -A, -S, -C + - Support for filesystems > 2GB + - FAT32 support */ + +/* Include the header files */ + +#include "version.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +# include + +#if __BYTE_ORDER == __BIG_ENDIAN + +#include +#ifdef __le16_to_cpu +/* ++roman: 2.1 kernel headers define these function, they're probably more + * efficient then coding the swaps machine-independently. */ +#define CF_LE_W __le16_to_cpu +#define CF_LE_L __le32_to_cpu +#define CT_LE_W __cpu_to_le16 +#define CT_LE_L __cpu_to_le32 +#else +#define CF_LE_W(v) ((((v) & 0xff) << 8) | (((v) >> 8) & 0xff)) +#define CF_LE_L(v) (((unsigned)(v)>>24) | (((unsigned)(v)>>8)&0xff00) | \ + (((unsigned)(v)<<8)&0xff0000) | ((unsigned)(v)<<24)) +#define CT_LE_W(v) CF_LE_W(v) +#define CT_LE_L(v) CF_LE_L(v) +#endif /* defined(__le16_to_cpu) */ + +#else + +#define CF_LE_W(v) (v) +#define CF_LE_L(v) (v) +#define CT_LE_W(v) (v) +#define CT_LE_L(v) (v) + +#endif /* __BIG_ENDIAN */ + +/* In earlier versions, an own llseek() was used, but glibc lseek() is + * sufficient (or even better :) for 64 bit offsets in the meantime */ +#define llseek lseek + +/* Constant definitions */ + +#define TRUE 1 /* Boolean constants */ +#define FALSE 0 + +#define TEST_BUFFER_BLOCKS 16 +#define HARD_SECTOR_SIZE 512 +#define SECTORS_PER_BLOCK ( BLOCK_SIZE / HARD_SECTOR_SIZE ) + + +/* Macro definitions */ + +/* Report a failure message and return a failure error code */ + +#define die( str ) fatal_error( "%s: " str "\n" ) + + +/* Mark a cluster in the FAT as bad */ + +#define mark_sector_bad( sector ) mark_FAT_sector( sector, FAT_BAD ) + +/* Compute ceil(a/b) */ + +inline int +cdiv (int a, int b) +{ + return (a + b - 1) / b; +} + +/* MS-DOS filesystem structures -- I included them here instead of + including linux/msdos_fs.h since that doesn't include some fields we + need */ + +#define ATTR_RO 1 /* read-only */ +#define ATTR_HIDDEN 2 /* hidden */ +#define ATTR_SYS 4 /* system */ +#define ATTR_VOLUME 8 /* volume label */ +#define ATTR_DIR 16 /* directory */ +#define ATTR_ARCH 32 /* archived */ + +#define ATTR_NONE 0 /* no attribute bits */ +#define ATTR_UNUSED (ATTR_VOLUME | ATTR_ARCH | ATTR_SYS | ATTR_HIDDEN) + /* attribute bits that are copied "as is" */ + +/* FAT values */ +#define FAT_EOF (atari_format ? 0x0fffffff : 0x0ffffff8) +#define FAT_BAD 0x0ffffff7 + +#define MSDOS_EXT_SIGN 0x29 /* extended boot sector signature */ +#define MSDOS_FAT12_SIGN "FAT12 " /* FAT12 filesystem signature */ +#define MSDOS_FAT16_SIGN "FAT16 " /* FAT16 filesystem signature */ +#define MSDOS_FAT32_SIGN "FAT32 " /* FAT32 filesystem signature */ + +#define BOOT_SIGN 0xAA55 /* Boot sector magic number */ + +#define MAX_CLUST_12 ((1 << 12) - 16) +#define MAX_CLUST_16 ((1 << 16) - 16) +#define MIN_CLUST_32 65529 +/* M$ says the high 4 bits of a FAT32 FAT entry are reserved and don't belong + * to the cluster number. So the max. cluster# is based on 2^28 */ +#define MAX_CLUST_32 ((1 << 28) - 16) + +#define FAT12_THRESHOLD 4085 + +#define OLDGEMDOS_MAX_SECTORS 32765 +#define GEMDOS_MAX_SECTORS 65531 +#define GEMDOS_MAX_SECTOR_SIZE (16*1024) + +#define BOOTCODE_SIZE 448 +#define BOOTCODE_FAT32_SIZE 420 + +/* __attribute__ ((packed)) is used on all structures to make gcc ignore any + * alignments */ + +struct msdos_volume_info { + __u8 drive_number; /* BIOS drive number */ + __u8 RESERVED; /* Unused */ + __u8 ext_boot_sign; /* 0x29 if fields below exist (DOS 3.3+) */ + __u8 volume_id[4]; /* Volume ID number */ + __u8 volume_label[11];/* Volume label */ + __u8 fs_type[8]; /* Typically FAT12 or FAT16 */ +} __attribute__ ((packed)); + +struct msdos_boot_sector +{ + __u8 boot_jump[3]; /* Boot strap short or near jump */ + __u8 system_id[8]; /* Name - can be used to special case + partition manager volumes */ + __u8 sector_size[2]; /* bytes per logical sector */ + __u8 cluster_size; /* sectors/cluster */ + __u16 reserved; /* reserved sectors */ + __u8 fats; /* number of FATs */ + __u8 dir_entries[2]; /* root directory entries */ + __u8 sectors[2]; /* number of sectors */ + __u8 media; /* media code (unused) */ + __u16 fat_length; /* sectors/FAT */ + __u16 secs_track; /* sectors per track */ + __u16 heads; /* number of heads */ + __u32 hidden; /* hidden sectors (unused) */ + __u32 total_sect; /* number of sectors (if sectors == 0) */ + union { + struct { + struct msdos_volume_info vi; + __u8 boot_code[BOOTCODE_SIZE]; + } __attribute__ ((packed)) _oldfat; + struct { + __u32 fat32_length; /* sectors/FAT */ + __u16 flags; /* bit 8: fat mirroring, low 4: active fat */ + __u8 version[2]; /* major, minor filesystem version */ + __u32 root_cluster; /* first cluster in root directory */ + __u16 info_sector; /* filesystem info sector */ + __u16 backup_boot; /* backup boot sector */ + __u16 reserved2[6]; /* Unused */ + struct msdos_volume_info vi; + __u8 boot_code[BOOTCODE_FAT32_SIZE]; + } __attribute__ ((packed)) _fat32; + } __attribute__ ((packed)) fstype; + __u16 boot_sign; +} __attribute__ ((packed)); +#define fat32 fstype._fat32 +#define oldfat fstype._oldfat + +struct fat32_fsinfo { + __u32 reserved1; /* Nothing as far as I can tell */ + __u32 signature; /* 0x61417272L */ + __u32 free_clusters; /* Free cluster count. -1 if unknown */ + __u32 next_cluster; /* Most recently allocated cluster. + * Unused under Linux. */ + __u32 reserved2[4]; +}; + +struct msdos_dir_entry + { + char name[8], ext[3]; /* name and extension */ + __u8 attr; /* attribute bits */ + __u8 lcase; /* Case for base and extension */ + __u8 ctime_ms; /* Creation time, milliseconds */ + __u16 ctime; /* Creation time */ + __u16 cdate; /* Creation date */ + __u16 adate; /* Last access date */ + __u16 starthi; /* high 16 bits of first cl. (FAT32) */ + __u16 time, date, start; /* time, date and first cluster */ + __u32 size; /* file size (in bytes) */ + } __attribute__ ((packed)); + +/* The "boot code" we put into the filesystem... it writes a message and + tells the user to try again */ + +char dummy_boot_jump[3] = { 0xeb, 0x3c, 0x90 }; + +char dummy_boot_jump_m68k[2] = { 0x60, 0x1c }; + +#define MSG_OFFSET_OFFSET 3 +char dummy_boot_code[BOOTCODE_SIZE] = + "\x0e" /* push cs */ + "\x1f" /* pop ds */ + "\xbe\x5b\x7c" /* mov si, offset message_txt */ + /* write_msg: */ + "\xac" /* lodsb */ + "\x22\xc0" /* and al, al */ + "\x74\x0b" /* jz key_press */ + "\x56" /* push si */ + "\xb4\x0e" /* mov ah, 0eh */ + "\xbb\x07\x00" /* mov bx, 0007h */ + "\xcd\x10" /* int 10h */ + "\x5e" /* pop si */ + "\xeb\xf0" /* jmp write_msg */ + /* key_press: */ + "\x32\xe4" /* xor ah, ah */ + "\xcd\x16" /* int 16h */ + "\xcd\x19" /* int 19h */ + "\xeb\xfe" /* foo: jmp foo */ + /* message_txt: */ + + "This is not a bootable disk. Please insert a bootable floppy and\r\n" + "press any key to try again ... \r\n"; + +#define MESSAGE_OFFSET 29 /* Offset of message in above code */ + +/* Global variables - the root of all evil :-) - see these and weep! */ + +static char *program_name = "mkdosfs"; /* Name of the program */ +static char *device_name = NULL; /* Name of the device on which to create the filesystem */ +static int atari_format = 0; /* Use Atari variation of MS-DOS FS format */ +static int check = FALSE; /* Default to no readablity checking */ +static int verbose = 0; /* Default to verbose mode off */ +static long volume_id; /* Volume ID number */ +static time_t create_time; /* Creation time */ +static struct timeval create_timeval; /* Creation time */ +static char volume_name[] = " "; /* Volume name */ +static unsigned long long blocks; /* Number of blocks in filesystem */ +static int sector_size = 512; /* Size of a logical sector */ +static int sector_size_set = 0; /* User selected sector size */ +static int backup_boot = 0; /* Sector# of backup boot sector */ +static int reserved_sectors = 0;/* Number of reserved sectors */ +static int badblocks = 0; /* Number of bad blocks in the filesystem */ +static int nr_fats = 2; /* Default number of FATs to produce */ +static int size_fat = 0; /* Size in bits of FAT entries */ +static int size_fat_by_user = 0; /* 1 if FAT size user selected */ +static int dev = -1; /* FS block device file handle */ +static int ignore_full_disk = 0; /* Ignore warning about 'full' disk devices */ +static off_t currently_testing = 0; /* Block currently being tested (if autodetect bad blocks) */ +static struct msdos_boot_sector bs; /* Boot sector data */ +static int start_data_sector; /* Sector number for the start of the data area */ +static int start_data_block; /* Block number for the start of the data area */ +static unsigned char *fat; /* File allocation table */ +static unsigned char *info_sector; /* FAT32 info sector */ +static struct msdos_dir_entry *root_dir; /* Root directory */ +static int size_root_dir; /* Size of the root directory in bytes */ +static int sectors_per_cluster = 0; /* Number of sectors per disk cluster */ +static int root_dir_entries = 0; /* Number of root directory entries */ +static char *blank_sector; /* Blank sector - all zeros */ +static int hidden_sectors = 0; /* Number of hidden sectors */ + + +/* Function prototype definitions */ + +static void fatal_error (const char *fmt_string) __attribute__((noreturn)); +static void mark_FAT_cluster (int cluster, unsigned int value); +static void mark_FAT_sector (int sector, unsigned int value); +static long do_check (char *buffer, int try, off_t current_block); +static void alarm_intr (int alnum); +static void check_blocks (void); +static void get_list_blocks (char *filename); +static int valid_offset (int fd, loff_t offset); +static unsigned long long count_blocks (char *filename); +static void check_mount (char *device_name); +static void establish_params (int device_num, int size); +static void setup_tables (void); +static void write_tables (void); + + +/* The function implementations */ + +/* Handle the reporting of fatal errors. Volatile to let gcc know that this doesn't return */ + +static void +fatal_error (const char *fmt_string) +{ + fprintf (stderr, fmt_string, program_name, device_name); + exit (1); /* The error exit code is 1! */ +} + + +/* Mark the specified cluster as having a particular value */ + +static void +mark_FAT_cluster (int cluster, unsigned int value) +{ + switch( size_fat ) { + case 12: + value &= 0x0fff; + if (((cluster * 3) & 0x1) == 0) + { + fat[3 * cluster / 2] = (unsigned char) (value & 0x00ff); + fat[(3 * cluster / 2) + 1] = (unsigned char) ((fat[(3 * cluster / 2) + 1] & 0x00f0) + | ((value & 0x0f00) >> 8)); + } + else + { + fat[3 * cluster / 2] = (unsigned char) ((fat[3 * cluster / 2] & 0x000f) | ((value & 0x000f) << 4)); + fat[(3 * cluster / 2) + 1] = (unsigned char) ((value & 0x0ff0) >> 4); + } + break; + + case 16: + value &= 0xffff; + fat[2 * cluster] = (unsigned char) (value & 0x00ff); + fat[(2 * cluster) + 1] = (unsigned char) (value >> 8); + break; + + case 32: + value &= 0xfffffff; + fat[4 * cluster] = (unsigned char) (value & 0x000000ff); + fat[(4 * cluster) + 1] = (unsigned char) ((value & 0x0000ff00) >> 8); + fat[(4 * cluster) + 2] = (unsigned char) ((value & 0x00ff0000) >> 16); + fat[(4 * cluster) + 3] = (unsigned char) ((value & 0xff000000) >> 24); + break; + + default: + die("Bad FAT size (not 12, 16, or 32)"); + } +} + + +/* Mark a specified sector as having a particular value in it's FAT entry */ + +static void +mark_FAT_sector (int sector, unsigned int value) +{ + int cluster; + + cluster = (sector - start_data_sector) / (int) (bs.cluster_size) / + (sector_size/HARD_SECTOR_SIZE); + if (cluster < 0) + die ("Invalid cluster number in mark_FAT_sector: probably bug!"); + + mark_FAT_cluster (cluster, value); +} + + +/* Perform a test on a block. Return the number of blocks that could be read successfully */ + +static long +do_check (char *buffer, int try, off_t current_block) +{ + long got; + + if (llseek (dev, current_block * BLOCK_SIZE, SEEK_SET) /* Seek to the correct location */ + != current_block * BLOCK_SIZE) + die ("seek failed during testing for blocks"); + + got = read (dev, buffer, try * BLOCK_SIZE); /* Try reading! */ + if (got < 0) + got = 0; + + if (got & (BLOCK_SIZE - 1)) + printf ("Unexpected values in do_check: probably bugs\n"); + got /= BLOCK_SIZE; + + return got; +} + + +/* Alarm clock handler - display the status of the quest for bad blocks! Then retrigger the alarm for five senconds + later (so we can come here again) */ + +static void +alarm_intr (int alnum) +{ + if (currently_testing >= blocks) + return; + + signal (SIGALRM, alarm_intr); + alarm (5); + if (!currently_testing) + return; + + printf ("%lld... ", (unsigned long long)currently_testing); + fflush (stdout); +} + + +static void +check_blocks (void) +{ + int try, got; + int i; + static char blkbuf[BLOCK_SIZE * TEST_BUFFER_BLOCKS]; + + if (verbose) + { + printf ("Searching for bad blocks "); + fflush (stdout); + } + currently_testing = 0; + if (verbose) + { + signal (SIGALRM, alarm_intr); + alarm (5); + } + try = TEST_BUFFER_BLOCKS; + while (currently_testing < blocks) + { + if (currently_testing + try > blocks) + try = blocks - currently_testing; + got = do_check (blkbuf, try, currently_testing); + currently_testing += got; + if (got == try) + { + try = TEST_BUFFER_BLOCKS; + continue; + } + else + try = 1; + if (currently_testing < start_data_block) + die ("bad blocks before data-area: cannot make fs"); + + for (i = 0; i < SECTORS_PER_BLOCK; i++) /* Mark all of the sectors in the block as bad */ + mark_sector_bad (currently_testing * SECTORS_PER_BLOCK + i); + badblocks++; + currently_testing++; + } + + if (verbose) + printf ("\n"); + + if (badblocks) + printf ("%d bad block%s\n", badblocks, + (badblocks > 1) ? "s" : ""); +} + + +static void +get_list_blocks (char *filename) +{ + int i; + FILE *listfile; + unsigned long blockno; + + listfile = fopen (filename, "r"); + if (listfile == (FILE *) NULL) + die ("Can't open file of bad blocks"); + + while (!feof (listfile)) + { + fscanf (listfile, "%ld\n", &blockno); + for (i = 0; i < SECTORS_PER_BLOCK; i++) /* Mark all of the sectors in the block as bad */ + mark_sector_bad (blockno * SECTORS_PER_BLOCK + i); + badblocks++; + } + fclose (listfile); + + if (badblocks) + printf ("%d bad block%s\n", badblocks, + (badblocks > 1) ? "s" : ""); +} + + +/* Given a file descriptor and an offset, check whether the offset is a valid offset for the file - return FALSE if it + isn't valid or TRUE if it is */ + +static int +valid_offset (int fd, loff_t offset) +{ + char ch; + + if (llseek (fd, offset, SEEK_SET) < 0) + return FALSE; + if (read (fd, &ch, 1) < 1) + return FALSE; + return TRUE; +} + + +/* Given a filename, look to see how many blocks of BLOCK_SIZE are present, returning the answer */ + +static unsigned long long +count_blocks (char *filename) +{ + off_t high, low; + int fd; + + if ((fd = open (filename, O_RDONLY)) < 0) + { + perror (filename); + exit (1); + } + + /* first try SEEK_END, which should work on most devices nowadays */ + if ((low = llseek(fd, 0, SEEK_END)) <= 0) { + low = 0; + for (high = 1; valid_offset (fd, high); high *= 2) + low = high; + while (low < high - 1) { + const loff_t mid = (low + high) / 2; + if (valid_offset (fd, mid)) + low = mid; + else + high = mid; + } + ++low; + } + + close (fd); + return low / BLOCK_SIZE; +} + + +/* Check to see if the specified device is currently mounted - abort if it is */ + +static void +check_mount (char *device_name) +{ + FILE *f; + struct mntent *mnt; + + if ((f = setmntent (MOUNTED, "r")) == NULL) + return; + while ((mnt = getmntent (f)) != NULL) + if (strcmp (device_name, mnt->mnt_fsname) == 0) + die ("%s contains a mounted file system."); + endmntent (f); +} + + +/* Establish the geometry and media parameters for the device */ + +static void +establish_params (int device_num,int size) +{ + long loop_size; + struct hd_geometry geometry; + struct floppy_struct param; + + if ((0 == device_num) || ((device_num & 0xff00) == 0x0200)) + /* file image or floppy disk */ + { + if (0 == device_num) + { + param.size = size/512; + switch(param.size) + { + case 720: + param.sect = 9 ; + param.head = 2; + break; + case 1440: + param.sect = 9; + param.head = 2; + break; + case 2400: + param.sect = 15; + param.head = 2; + break; + case 2880: + param.sect = 18; + param.head = 2; + break; + case 5760: + param.sect = 36; + param.head = 2; + break; + default: + /* fake values */ + param.sect = 32; + param.head = 64; + break; + } + + } + else /* is a floppy diskette */ + { + if (ioctl (dev, FDGETPRM, ¶m)) /* Can we get the diskette geometry? */ + die ("unable to get diskette geometry for '%s'"); + } + bs.secs_track = CT_LE_W(param.sect); /* Set up the geometry information */ + bs.heads = CT_LE_W(param.head); + switch (param.size) /* Set up the media descriptor byte */ + { + case 720: /* 5.25", 2, 9, 40 - 360K */ + bs.media = (char) 0xfd; + bs.cluster_size = (char) 2; + bs.dir_entries[0] = (char) 112; + bs.dir_entries[1] = (char) 0; + break; + + case 1440: /* 3.5", 2, 9, 80 - 720K */ + bs.media = (char) 0xf9; + bs.cluster_size = (char) 2; + bs.dir_entries[0] = (char) 112; + bs.dir_entries[1] = (char) 0; + break; + + case 2400: /* 5.25", 2, 15, 80 - 1200K */ + bs.media = (char) 0xf9; + bs.cluster_size = (char)(atari_format ? 2 : 1); + bs.dir_entries[0] = (char) 224; + bs.dir_entries[1] = (char) 0; + break; + + case 5760: /* 3.5", 2, 36, 80 - 2880K */ + bs.media = (char) 0xf0; + bs.cluster_size = (char) 2; + bs.dir_entries[0] = (char) 224; + bs.dir_entries[1] = (char) 0; + break; + + case 2880: /* 3.5", 2, 18, 80 - 1440K */ + floppy_default: + bs.media = (char) 0xf0; + bs.cluster_size = (char)(atari_format ? 2 : 1); + bs.dir_entries[0] = (char) 224; + bs.dir_entries[1] = (char) 0; + break; + + default: /* Anything else */ + if (0 == device_num) + goto def_hd_params; + else + goto floppy_default; + } + } + else if ((device_num & 0xff00) == 0x0700) /* This is a loop device */ + { + if (ioctl (dev, BLKGETSIZE, &loop_size)) + die ("unable to get loop device size"); + + switch (loop_size) /* Assuming the loop device -> floppy later */ + { + case 720: /* 5.25", 2, 9, 40 - 360K */ + bs.secs_track = CF_LE_W(9); + bs.heads = CF_LE_W(2); + bs.media = (char) 0xfd; + bs.cluster_size = (char) 2; + bs.dir_entries[0] = (char) 112; + bs.dir_entries[1] = (char) 0; + break; + + case 1440: /* 3.5", 2, 9, 80 - 720K */ + bs.secs_track = CF_LE_W(9); + bs.heads = CF_LE_W(2); + bs.media = (char) 0xf9; + bs.cluster_size = (char) 2; + bs.dir_entries[0] = (char) 112; + bs.dir_entries[1] = (char) 0; + break; + + case 2400: /* 5.25", 2, 15, 80 - 1200K */ + bs.secs_track = CF_LE_W(15); + bs.heads = CF_LE_W(2); + bs.media = (char) 0xf9; + bs.cluster_size = (char)(atari_format ? 2 : 1); + bs.dir_entries[0] = (char) 224; + bs.dir_entries[1] = (char) 0; + break; + + case 5760: /* 3.5", 2, 36, 80 - 2880K */ + bs.secs_track = CF_LE_W(36); + bs.heads = CF_LE_W(2); + bs.media = (char) 0xf0; + bs.cluster_size = (char) 2; + bs.dir_entries[0] = (char) 224; + bs.dir_entries[1] = (char) 0; + break; + + case 2880: /* 3.5", 2, 18, 80 - 1440K */ + bs.secs_track = CF_LE_W(18); + bs.heads = CF_LE_W(2); + bs.media = (char) 0xf0; + bs.cluster_size = (char)(atari_format ? 2 : 1); + bs.dir_entries[0] = (char) 224; + bs.dir_entries[1] = (char) 0; + break; + + default: /* Anything else: default hd setup */ + printf("Loop device does not match a floppy size, using " + "default hd params\n"); + bs.secs_track = CT_LE_W(32); /* these are fake values... */ + bs.heads = CT_LE_W(64); + goto def_hd_params; + } + } + else + /* Must be a hard disk then! */ + { + /* Can we get the drive geometry? (Note I'm not too sure about */ + /* whether to use HDIO_GETGEO or HDIO_REQ) */ + if (ioctl (dev, HDIO_GETGEO, &geometry) || geometry.sectors == 0 || geometry.heads == 0) { + printf ("unable to get drive geometry, using default 255/63\n"); + bs.secs_track = CT_LE_W(63); + bs.heads = CT_LE_W(255); + } + else { + bs.secs_track = CT_LE_W(geometry.sectors); /* Set up the geometry information */ + bs.heads = CT_LE_W(geometry.heads); + } + def_hd_params: + bs.media = (char) 0xf8; /* Set up the media descriptor for a hard drive */ + bs.dir_entries[0] = (char) 0; /* Default to 512 entries */ + bs.dir_entries[1] = (char) 2; + if (!size_fat && blocks*SECTORS_PER_BLOCK > 1064960) { + if (verbose) printf("Auto-selecting FAT32 for large filesystem\n"); + size_fat = 32; + } + if (size_fat == 32) { + /* For FAT32, try to do the same as M$'s format command + * (see http://www.win.tue.nl/~aeb/linux/fs/fat/fatgen103.pdf p. 20): + * fs size <= 260M: 0.5k clusters + * fs size <= 8G: 4k clusters + * fs size <= 16G: 8k clusters + * fs size > 16G: 16k clusters + */ + unsigned long sz_mb = + (blocks+(1<<(20-BLOCK_SIZE_BITS))-1) >> (20-BLOCK_SIZE_BITS); + bs.cluster_size = sz_mb > 16*1024 ? 32 : + sz_mb > 8*1024 ? 16 : + sz_mb > 260 ? 8 : + 1; + } + else { + /* FAT12 and FAT16: start at 4 sectors per cluster */ + bs.cluster_size = (char) 4; + } + } +} + + +/* Create the filesystem data tables */ + +static void +setup_tables (void) +{ + unsigned num_sectors; + unsigned cluster_count = 0, fat_length; + unsigned fatdata; /* Sectors for FATs + data area */ + struct tm *ctime; + struct msdos_volume_info *vi = (size_fat == 32 ? &bs.fat32.vi : &bs.oldfat.vi); + + if (atari_format) + /* On Atari, the first few bytes of the boot sector are assigned + * differently: The jump code is only 2 bytes (and m68k machine code + * :-), then 6 bytes filler (ignored), then 3 byte serial number. */ + memcpy( bs.system_id-1, "mkdosf", 6 ); + else + strcpy (bs.system_id, "mkdosfs"); + if (sectors_per_cluster) + bs.cluster_size = (char) sectors_per_cluster; + if (size_fat == 32) + { + /* Under FAT32, the root dir is in a cluster chain, and this is + * signalled by bs.dir_entries being 0. */ + bs.dir_entries[0] = bs.dir_entries[1] = (char) 0; + root_dir_entries = 0; + } + else if (root_dir_entries) + { + /* Override default from establish_params() */ + bs.dir_entries[0] = (char) (root_dir_entries & 0x00ff); + bs.dir_entries[1] = (char) ((root_dir_entries & 0xff00) >> 8); + } + else + root_dir_entries = bs.dir_entries[0] + (bs.dir_entries[1] << 8); + + if (atari_format) { + bs.system_id[5] = (unsigned char) (volume_id & 0x000000ff); + bs.system_id[6] = (unsigned char) ((volume_id & 0x0000ff00) >> 8); + bs.system_id[7] = (unsigned char) ((volume_id & 0x00ff0000) >> 16); + } + else { + vi->volume_id[0] = (unsigned char) (volume_id & 0x000000ff); + vi->volume_id[1] = (unsigned char) ((volume_id & 0x0000ff00) >> 8); + vi->volume_id[2] = (unsigned char) ((volume_id & 0x00ff0000) >> 16); + vi->volume_id[3] = (unsigned char) (volume_id >> 24); + } + + if (!atari_format) { + memcpy(vi->volume_label, volume_name, 11); + + memcpy(bs.boot_jump, dummy_boot_jump, 3); + /* Patch in the correct offset to the boot code */ + bs.boot_jump[1] = ((size_fat == 32 ? + (char *)&bs.fat32.boot_code : + (char *)&bs.oldfat.boot_code) - + (char *)&bs) - 2; + + if (size_fat == 32) { + int offset = (char *)&bs.fat32.boot_code - + (char *)&bs + MESSAGE_OFFSET + 0x7c00; + if (dummy_boot_code[BOOTCODE_FAT32_SIZE-1]) + printf ("Warning: message too long; truncated\n"); + dummy_boot_code[BOOTCODE_FAT32_SIZE-1] = 0; + memcpy(bs.fat32.boot_code, dummy_boot_code, BOOTCODE_FAT32_SIZE); + bs.fat32.boot_code[MSG_OFFSET_OFFSET] = offset & 0xff; + bs.fat32.boot_code[MSG_OFFSET_OFFSET+1] = offset >> 8; + } + else { + memcpy(bs.oldfat.boot_code, dummy_boot_code, BOOTCODE_SIZE); + } + bs.boot_sign = CT_LE_W(BOOT_SIGN); + } + else { + memcpy(bs.boot_jump, dummy_boot_jump_m68k, 2); + } + if (verbose >= 2) + printf( "Boot jump code is %02x %02x\n", + bs.boot_jump[0], bs.boot_jump[1] ); + + if (!reserved_sectors) + reserved_sectors = (size_fat == 32) ? 32 : 1; + else { + if (size_fat == 32 && reserved_sectors < 2) + die("On FAT32 at least 2 reserved sectors are needed."); + } + bs.reserved = CT_LE_W(reserved_sectors); + if (verbose >= 2) + printf( "Using %d reserved sectors\n", reserved_sectors ); + bs.fats = (char) nr_fats; + if (!atari_format || size_fat == 32) + bs.hidden = CT_LE_L(hidden_sectors); + else { + /* In Atari format, hidden is a 16 bit field */ + __u16 hidden = CT_LE_W(hidden_sectors); + if (hidden_sectors & ~0xffff) + die("#hidden doesn't fit in 16bit field of Atari format\n"); + memcpy( &bs.hidden, &hidden, 2 ); + } + + num_sectors = (long long)blocks*BLOCK_SIZE/sector_size; + if (!atari_format) { + unsigned fatlength12, fatlength16, fatlength32; + unsigned maxclust12, maxclust16, maxclust32; + unsigned clust12, clust16, clust32; + int maxclustsize; + + fatdata = num_sectors - cdiv (root_dir_entries * 32, sector_size) - + reserved_sectors; + + if (sectors_per_cluster) + bs.cluster_size = maxclustsize = sectors_per_cluster; + else + /* An initial guess for bs.cluster_size should already be set */ + maxclustsize = 128; + + if (verbose >= 2) + printf( "%d sectors for FAT+data, starting with %d sectors/cluster\n", + fatdata, bs.cluster_size ); + do { + if (verbose >= 2) + printf( "Trying with %d sectors/cluster:\n", bs.cluster_size ); + + /* The factor 2 below avoids cut-off errors for nr_fats == 1. + * The "nr_fats*3" is for the reserved first two FAT entries */ + clust12 = 2*((long long) fatdata *sector_size + nr_fats*3) / + (2*(int) bs.cluster_size * sector_size + nr_fats*3); + fatlength12 = cdiv (((clust12+2) * 3 + 1) >> 1, sector_size); + /* Need to recalculate number of clusters, since the unused parts of the + * FATS and data area together could make up space for an additional, + * not really present cluster. */ + clust12 = (fatdata - nr_fats*fatlength12)/bs.cluster_size; + maxclust12 = (fatlength12 * 2 * sector_size) / 3; + if (maxclust12 > MAX_CLUST_12) + maxclust12 = MAX_CLUST_12; + if (verbose >= 2) + printf( "FAT12: #clu=%u, fatlen=%u, maxclu=%u, limit=%u\n", + clust12, fatlength12, maxclust12, MAX_CLUST_12 ); + if (clust12 > maxclust12-2) { + clust12 = 0; + if (verbose >= 2) + printf( "FAT12: too much clusters\n" ); + } + + clust16 = ((long long) fatdata *sector_size + nr_fats*4) / + ((int) bs.cluster_size * sector_size + nr_fats*2); + fatlength16 = cdiv ((clust16+2) * 2, sector_size); + /* Need to recalculate number of clusters, since the unused parts of the + * FATS and data area together could make up space for an additional, + * not really present cluster. */ + clust16 = (fatdata - nr_fats*fatlength16)/bs.cluster_size; + maxclust16 = (fatlength16 * sector_size) / 2; + if (maxclust16 > MAX_CLUST_16) + maxclust16 = MAX_CLUST_16; + if (verbose >= 2) + printf( "FAT16: #clu=%u, fatlen=%u, maxclu=%u, limit=%u\n", + clust16, fatlength16, maxclust16, MAX_CLUST_16 ); + if (clust16 > maxclust16-2) { + if (verbose >= 2) + printf( "FAT16: too much clusters\n" ); + clust16 = 0; + } + /* The < 4078 avoids that the filesystem will be misdetected as having a + * 12 bit FAT. */ + if (clust16 < FAT12_THRESHOLD && !(size_fat_by_user && size_fat == 16)) { + if (verbose >= 2) + printf( clust16 < FAT12_THRESHOLD ? + "FAT16: would be misdetected as FAT12\n" : + "FAT16: too much clusters\n" ); + clust16 = 0; + } + + clust32 = ((long long) fatdata *sector_size + nr_fats*8) / + ((int) bs.cluster_size * sector_size + nr_fats*4); + fatlength32 = cdiv ((clust32+2) * 4, sector_size); + /* Need to recalculate number of clusters, since the unused parts of the + * FATS and data area together could make up space for an additional, + * not really present cluster. */ + clust32 = (fatdata - nr_fats*fatlength32)/bs.cluster_size; + maxclust32 = (fatlength32 * sector_size) / 4; + if (maxclust32 > MAX_CLUST_32) + maxclust32 = MAX_CLUST_32; + if (clust32 && clust32 < MIN_CLUST_32 && !(size_fat_by_user && size_fat == 32)) { + clust32 = 0; + if (verbose >= 2) + printf( "FAT32: not enough clusters (%d)\n", MIN_CLUST_32); + } + if (verbose >= 2) + printf( "FAT32: #clu=%u, fatlen=%u, maxclu=%u, limit=%u\n", + clust32, fatlength32, maxclust32, MAX_CLUST_32 ); + if (clust32 > maxclust32) { + clust32 = 0; + if (verbose >= 2) + printf( "FAT32: too much clusters\n" ); + } + + if ((clust12 && (size_fat == 0 || size_fat == 12)) || + (clust16 && (size_fat == 0 || size_fat == 16)) || + (clust32 && size_fat == 32)) + break; + + bs.cluster_size <<= 1; + } while (bs.cluster_size && bs.cluster_size <= maxclustsize); + + /* Use the optimal FAT size if not specified; + * FAT32 is (not yet) choosen automatically */ + if (!size_fat) { + size_fat = (clust16 > clust12) ? 16 : 12; + if (verbose >= 2) + printf( "Choosing %d bits for FAT\n", size_fat ); + } + + switch (size_fat) { + case 12: + cluster_count = clust12; + fat_length = fatlength12; + bs.fat_length = CT_LE_W(fatlength12); + memcpy(vi->fs_type, MSDOS_FAT12_SIGN, 8); + break; + + case 16: + if (clust16 < FAT12_THRESHOLD) { + if (size_fat_by_user) { + fprintf( stderr, "WARNING: Not enough clusters for a " + "16 bit FAT! The filesystem will be\n" + "misinterpreted as having a 12 bit FAT without " + "mount option \"fat=16\".\n" ); + } + else { + fprintf( stderr, "This filesystem has an unfortunate size. " + "A 12 bit FAT cannot provide\n" + "enough clusters, but a 16 bit FAT takes up a little " + "bit more space so that\n" + "the total number of clusters becomes less than the " + "threshold value for\n" + "distinction between 12 and 16 bit FATs.\n" ); + die( "Make the file system a bit smaller manually." ); + } + } + cluster_count = clust16; + fat_length = fatlength16; + bs.fat_length = CT_LE_W(fatlength16); + memcpy(vi->fs_type, MSDOS_FAT16_SIGN, 8); + break; + + case 32: + if (clust32 < MIN_CLUST_32) + fprintf(stderr, "WARNING: Not enough clusters for a 32 bit FAT!\n"); + cluster_count = clust32; + fat_length = fatlength32; + bs.fat_length = CT_LE_W(0); + bs.fat32.fat32_length = CT_LE_L(fatlength32); + memcpy(vi->fs_type, MSDOS_FAT32_SIGN, 8); + break; + + default: + die("FAT not 12, 16 or 32 bits"); + } + } + else { + unsigned clusters, maxclust; + + /* GEMDOS always uses a 12 bit FAT on floppies, and always a 16 bit FAT on + * hard disks. So use 12 bit if the size of the file system suggests that + * this fs is for a floppy disk, if the user hasn't explicitly requested a + * size. + */ + if (!size_fat) + size_fat = (num_sectors == 1440 || num_sectors == 2400 || + num_sectors == 2880 || num_sectors == 5760) ? 12 : 16; + if (verbose >= 2) + printf( "Choosing %d bits for FAT\n", size_fat ); + + /* Atari format: cluster size should be 2, except explicitly requested by + * the user, since GEMDOS doesn't like other cluster sizes very much. + * Instead, tune the sector size for the FS to fit. + */ + bs.cluster_size = sectors_per_cluster ? sectors_per_cluster : 2; + if (!sector_size_set) { + while( num_sectors > GEMDOS_MAX_SECTORS ) { + num_sectors >>= 1; + sector_size <<= 1; + } + } + if (verbose >= 2) + printf( "Sector size must be %d to have less than %d log. sectors\n", + sector_size, GEMDOS_MAX_SECTORS ); + + /* Check if there are enough FAT indices for how much clusters we have */ + do { + fatdata = num_sectors - cdiv (root_dir_entries * 32, sector_size) - + reserved_sectors; + /* The factor 2 below avoids cut-off errors for nr_fats == 1 and + * size_fat == 12 + * The "2*nr_fats*size_fat/8" is for the reserved first two FAT entries + */ + clusters = (2*((long long)fatdata*sector_size - 2*nr_fats*size_fat/8)) / + (2*((int)bs.cluster_size*sector_size + nr_fats*size_fat/8)); + fat_length = cdiv( (clusters+2)*size_fat/8, sector_size ); + /* Need to recalculate number of clusters, since the unused parts of the + * FATS and data area together could make up space for an additional, + * not really present cluster. */ + clusters = (fatdata - nr_fats*fat_length)/bs.cluster_size; + maxclust = (fat_length*sector_size*8)/size_fat; + if (verbose >= 2) + printf( "ss=%d: #clu=%d, fat_len=%d, maxclu=%d\n", + sector_size, clusters, fat_length, maxclust ); + + /* last 10 cluster numbers are special (except FAT32: 4 high bits rsvd); + * first two numbers are reserved */ + if (maxclust <= (size_fat == 32 ? MAX_CLUST_32 : (1<= 2) + printf( clusters > maxclust-2 ? + "Too many clusters\n" : "FAT too big\n" ); + + /* need to increment sector_size once more to */ + if (sector_size_set) + die( "With this sector size, the maximum number of FAT entries " + "would be exceeded." ); + num_sectors >>= 1; + sector_size <<= 1; + } while( sector_size <= GEMDOS_MAX_SECTOR_SIZE ); + + if (sector_size > GEMDOS_MAX_SECTOR_SIZE) + die( "Would need a sector size > 16k, which GEMDOS can't work with"); + + cluster_count = clusters; + if (size_fat != 32) + bs.fat_length = CT_LE_W(fat_length); + else { + bs.fat_length = 0; + bs.fat32.fat32_length = CT_LE_L(fat_length); + } + } + + bs.sector_size[0] = (char) (sector_size & 0x00ff); + bs.sector_size[1] = (char) ((sector_size & 0xff00) >> 8); + + if (size_fat == 32) + { + /* set up additional FAT32 fields */ + bs.fat32.flags = CT_LE_W(0); + bs.fat32.version[0] = 0; + bs.fat32.version[1] = 0; + bs.fat32.root_cluster = CT_LE_L(2); + bs.fat32.info_sector = CT_LE_W(1); + if (!backup_boot) + backup_boot = (reserved_sectors >= 7) ? 6 : + (reserved_sectors >= 2) ? reserved_sectors-1 : 0; + else + { + if (backup_boot == 1) + die("Backup boot sector must be after sector 1"); + else if (backup_boot >= reserved_sectors) + die("Backup boot sector must be a reserved sector"); + } + if (verbose >= 2) + printf( "Using sector %d as backup boot sector (0 = none)\n", + backup_boot ); + bs.fat32.backup_boot = CT_LE_W(backup_boot); + memset( &bs.fat32.reserved2, 0, sizeof(bs.fat32.reserved2) ); + } + + if (atari_format) { + /* Just some consistency checks */ + if (num_sectors >= GEMDOS_MAX_SECTORS) + die( "GEMDOS can't handle more than 65531 sectors" ); + else if (num_sectors >= OLDGEMDOS_MAX_SECTORS) + printf( "Warning: More than 32765 sector need TOS 1.04 " + "or higher.\n" ); + } + if (num_sectors >= 65536) + { + bs.sectors[0] = (char) 0; + bs.sectors[1] = (char) 0; + bs.total_sect = CT_LE_L(num_sectors); + } + else + { + bs.sectors[0] = (char) (num_sectors & 0x00ff); + bs.sectors[1] = (char) ((num_sectors & 0xff00) >> 8); + if (!atari_format) + bs.total_sect = CT_LE_L(0); + } + + if (!atari_format) + vi->ext_boot_sign = MSDOS_EXT_SIGN; + + if (!cluster_count) + { + if (sectors_per_cluster) /* If yes, die if we'd spec'd sectors per cluster */ + die ("Too many clusters for file system - try more sectors per cluster"); + else + die ("Attempting to create a too large file system"); + } + + + /* The two following vars are in hard sectors, i.e. 512 byte sectors! */ + start_data_sector = (reserved_sectors + nr_fats * fat_length) * + (sector_size/HARD_SECTOR_SIZE); + start_data_block = (start_data_sector + SECTORS_PER_BLOCK - 1) / + SECTORS_PER_BLOCK; + + if (blocks < start_data_block + 32) /* Arbitrary undersize file system! */ + die ("Too few blocks for viable file system"); + + if (verbose) + { + printf("%s has %d head%s and %d sector%s per track,\n", + device_name, CF_LE_W(bs.heads), (CF_LE_W(bs.heads) != 1) ? "s" : "", + CF_LE_W(bs.secs_track), (CF_LE_W(bs.secs_track) != 1) ? "s" : ""); + printf("logical sector size is %d,\n",sector_size); + printf("using 0x%02x media descriptor, with %d sectors;\n", + (int) (bs.media), num_sectors); + printf("file system has %d %d-bit FAT%s and %d sector%s per cluster.\n", + (int) (bs.fats), size_fat, (bs.fats != 1) ? "s" : "", + (int) (bs.cluster_size), (bs.cluster_size != 1) ? "s" : ""); + printf ("FAT size is %d sector%s, and provides %d cluster%s.\n", + fat_length, (fat_length != 1) ? "s" : "", + cluster_count, (cluster_count != 1) ? "s" : ""); + if (size_fat != 32) + printf ("Root directory contains %d slots.\n", + (int) (bs.dir_entries[0]) + (int) (bs.dir_entries[1]) * 256); + printf ("Volume ID is %08lx, ", volume_id & + (atari_format ? 0x00ffffff : 0xffffffff)); + if ( strcmp(volume_name, " ") ) + printf("volume label %s.\n", volume_name); + else + printf("no volume label.\n"); + } + + /* Make the file allocation tables! */ + + if ((fat = (unsigned char *) malloc (fat_length * sector_size)) == NULL) + die ("unable to allocate space for FAT image in memory"); + + memset( fat, 0, fat_length * sector_size ); + + mark_FAT_cluster (0, 0xffffffff); /* Initial fat entries */ + mark_FAT_cluster (1, 0xffffffff); + fat[0] = (unsigned char) bs.media; /* Put media type in first byte! */ + if (size_fat == 32) { + /* Mark cluster 2 as EOF (used for root dir) */ + mark_FAT_cluster (2, FAT_EOF); + } + + /* Make the root directory entries */ + + size_root_dir = (size_fat == 32) ? + bs.cluster_size*sector_size : + (((int)bs.dir_entries[1]*256+(int)bs.dir_entries[0]) * + sizeof (struct msdos_dir_entry)); + if ((root_dir = (struct msdos_dir_entry *) malloc (size_root_dir)) == NULL) + { + free (fat); /* Tidy up before we die! */ + die ("unable to allocate space for root directory in memory"); + } + + memset(root_dir, 0, size_root_dir); + if ( memcmp(volume_name, " ", 11) ) + { + struct msdos_dir_entry *de = &root_dir[0]; + memcpy(de->name, volume_name, 11); + de->attr = ATTR_VOLUME; + ctime = localtime(&create_time); + de->time = CT_LE_W((unsigned short)((ctime->tm_sec >> 1) + + (ctime->tm_min << 5) + (ctime->tm_hour << 11))); + de->date = CT_LE_W((unsigned short)(ctime->tm_mday + + ((ctime->tm_mon+1) << 5) + + ((ctime->tm_year-80) << 9))); + de->ctime_ms = 0; + de->ctime = de->time; + de->cdate = de->date; + de->adate = de->date; + de->starthi = CT_LE_W(0); + de->start = CT_LE_W(0); + de->size = CT_LE_L(0); + } + + if (size_fat == 32) { + /* For FAT32, create an info sector */ + struct fat32_fsinfo *info; + + if (!(info_sector = malloc( sector_size ))) + die("Out of memory"); + memset(info_sector, 0, sector_size); + /* fsinfo structure is at offset 0x1e0 in info sector by observation */ + info = (struct fat32_fsinfo *)(info_sector + 0x1e0); + + /* Info sector magic */ + info_sector[0] = 'R'; + info_sector[1] = 'R'; + info_sector[2] = 'a'; + info_sector[3] = 'A'; + + /* Magic for fsinfo structure */ + info->signature = CT_LE_L(0x61417272); + /* We've allocated cluster 2 for the root dir. */ + info->free_clusters = CT_LE_L(cluster_count - 1); + info->next_cluster = CT_LE_L(2); + + /* Info sector also must have boot sign */ + *(__u16 *)(info_sector + 0x1fe) = CT_LE_W(BOOT_SIGN); + } + + if (!(blank_sector = malloc( sector_size ))) + die( "Out of memory" ); + memset(blank_sector, 0, sector_size); +} + + +/* Write the new filesystem's data tables to wherever they're going to end up! */ + +#define error(str) \ + do { \ + free (fat); \ + if (info_sector) free (info_sector); \ + free (root_dir); \ + die (str); \ + } while(0) + +#define seekto(pos,errstr) \ + do { \ + loff_t __pos = (pos); \ + if (llseek (dev, __pos, SEEK_SET) != __pos) \ + error ("seek to " errstr " failed whilst writing tables"); \ + } while(0) + +#define writebuf(buf,size,errstr) \ + do { \ + int __size = (size); \ + if (write (dev, buf, __size) != __size) \ + error ("failed whilst writing " errstr); \ + } while(0) + + +static void +write_tables (void) +{ + int x; + int fat_length; + + fat_length = (size_fat == 32) ? + CF_LE_L(bs.fat32.fat32_length) : CF_LE_W(bs.fat_length); + + seekto( 0, "start of device" ); + /* clear all reserved sectors */ + for( x = 0; x < reserved_sectors; ++x ) + writebuf( blank_sector, sector_size, "reserved sector" ); + /* seek back to sector 0 and write the boot sector */ + seekto( 0, "boot sector" ); + writebuf( (char *) &bs, sizeof (struct msdos_boot_sector), "boot sector" ); + /* on FAT32, write the info sector and backup boot sector */ + if (size_fat == 32) + { + seekto( CF_LE_W(bs.fat32.info_sector)*sector_size, "info sector" ); + writebuf( info_sector, 512, "info sector" ); + if (backup_boot != 0) + { + seekto( backup_boot*sector_size, "backup boot sector" ); + writebuf( (char *) &bs, sizeof (struct msdos_boot_sector), + "backup boot sector" ); + } + } + /* seek to start of FATS and write them all */ + seekto( reserved_sectors*sector_size, "first FAT" ); + for (x = 1; x <= nr_fats; x++) + writebuf( fat, fat_length * sector_size, "FAT" ); + /* Write the root directory directly after the last FAT. This is the root + * dir area on FAT12/16, and the first cluster on FAT32. */ + writebuf( (char *) root_dir, size_root_dir, "root directory" ); + + if (blank_sector) free( blank_sector ); + if (info_sector) free( info_sector ); + free (root_dir); /* Free up the root directory space from setup_tables */ + free (fat); /* Free up the fat table space reserved during setup_tables */ +} + + +/* Report the command usage and return a failure error code */ + +void +usage (void) +{ + fatal_error("\ +Usage: mkdosfs [-A] [-c] [-C] [-v] [-I] [-l bad-block-file] [-b backup-boot-sector]\n\ + [-m boot-msg-file] [-n volume-name] [-i volume-id]\n\ + [-s sectors-per-cluster] [-S logical-sector-size] [-f number-of-FATs]\n\ + [-h hidden-sectors] [-F fat-size] [-r root-dir-entries] [-R reserved-sectors]\n\ + /dev/name [blocks]\n"); +} + +/* + * ++roman: On m68k, check if this is an Atari; if yes, turn on Atari variant + * of MS-DOS filesystem by default. + */ +static void check_atari( void ) +{ +#ifdef __mc68000__ + FILE *f; + char line[128], *p; + + if (!(f = fopen( "/proc/hardware", "r" ))) { + perror( "/proc/hardware" ); + return; + } + + while( fgets( line, sizeof(line), f ) ) { + if (strncmp( line, "Model:", 6 ) == 0) { + p = line + 6; + p += strspn( p, " \t" ); + if (strncmp( p, "Atari ", 6 ) == 0) + atari_format = 1; + break; + } + } + fclose( f ); +#endif +} + +/* The "main" entry point into the utility - we pick up the options and attempt to process them in some sort of sensible + way. In the event that some/all of the options are invalid we need to tell the user so that something can be done! */ + +int +main (int argc, char **argv) +{ + int c; + char *tmp; + char *listfile = NULL; + FILE *msgfile; + struct stat statbuf; + int i = 0, pos, ch; + int create = 0; + unsigned long long cblocks; + int min_sector_size; + + if (argc && *argv) { /* What's the program name? */ + char *p; + program_name = *argv; + if ((p = strrchr( program_name, '/' ))) + program_name = p+1; + } + + gettimeofday(&create_timeval, NULL); + create_time = create_timeval.tv_sec; + volume_id = (u_int32_t)( (create_timeval.tv_sec << 20) | create_timeval.tv_usec ); /* Default volume ID = creation time, fudged for more uniqueness */ + check_atari(); + + printf ("%s " VERSION " (" VERSION_DATE ")\n", + program_name); + + while ((c = getopt (argc, argv, "Ab:cCf:F:Ii:l:m:n:r:R:s:S:h:v")) != EOF) + /* Scan the command line for options */ + switch (c) + { + case 'A': /* toggle Atari format */ + atari_format = !atari_format; + break; + + case 'b': /* b : location of backup boot sector */ + backup_boot = (int) strtol (optarg, &tmp, 0); + if (*tmp || backup_boot < 2 || backup_boot > 0xffff) + { + printf ("Bad location for backup boot sector : %s\n", optarg); + usage (); + } + break; + + case 'c': /* c : Check FS as we build it */ + check = TRUE; + break; + + case 'C': /* C : Create a new file */ + create = TRUE; + break; + + case 'f': /* f : Choose number of FATs */ + nr_fats = (int) strtol (optarg, &tmp, 0); + if (*tmp || nr_fats < 1 || nr_fats > 4) + { + printf ("Bad number of FATs : %s\n", optarg); + usage (); + } + break; + + case 'F': /* F : Choose FAT size */ + size_fat = (int) strtol (optarg, &tmp, 0); + if (*tmp || (size_fat != 12 && size_fat != 16 && size_fat != 32)) + { + printf ("Bad FAT type : %s\n", optarg); + usage (); + } + size_fat_by_user = 1; + break; + + case 'h': /* h : number of hidden sectors */ + hidden_sectors = (int) strtol (optarg, &tmp, 0); + if ( *tmp || hidden_sectors < 0 ) + { + printf("Bad number of hidden sectors : %s\n", optarg); + usage (); + } + break; + + case 'I': + ignore_full_disk = 1; + break; + + case 'i': /* i : specify volume ID */ + volume_id = strtoul(optarg, &tmp, 16); + if ( *tmp ) + { + printf("Volume ID must be a hexadecimal number\n"); + usage(); + } + break; + + case 'l': /* l : Bad block filename */ + listfile = optarg; + break; + + case 'm': /* m : Set boot message */ + if ( strcmp(optarg, "-") ) + { + msgfile = fopen(optarg, "r"); + if ( !msgfile ) + perror(optarg); + } + else + msgfile = stdin; + + if ( msgfile ) + { + /* The boot code ends at offset 448 and needs a null terminator */ + i = MESSAGE_OFFSET; + pos = 0; /* We are at beginning of line */ + do + { + ch = getc(msgfile); + switch (ch) + { + case '\r': /* Ignore CRs */ + case '\0': /* and nulls */ + break; + + case '\n': /* LF -> CR+LF if necessary */ + if ( pos ) /* If not at beginning of line */ + { + dummy_boot_code[i++] = '\r'; + pos = 0; + } + dummy_boot_code[i++] = '\n'; + break; + + case '\t': /* Expand tabs */ + do + { + dummy_boot_code[i++] = ' '; + pos++; + } + while ( pos % 8 && i < BOOTCODE_SIZE-1 ); + break; + + case EOF: + dummy_boot_code[i++] = '\0'; /* Null terminator */ + break; + + default: + dummy_boot_code[i++] = ch; /* Store character */ + pos++; /* Advance position */ + break; + } + } + while ( ch != EOF && i < BOOTCODE_SIZE-1 ); + + /* Fill up with zeros */ + while( i < BOOTCODE_SIZE-1 ) + dummy_boot_code[i++] = '\0'; + dummy_boot_code[BOOTCODE_SIZE-1] = '\0'; /* Just in case */ + + if ( ch != EOF ) + printf ("Warning: message too long; truncated\n"); + + if ( msgfile != stdin ) + fclose(msgfile); + } + break; + + case 'n': /* n : Volume name */ + sprintf(volume_name, "%-11.11s", optarg); + break; + + case 'r': /* r : Root directory entries */ + root_dir_entries = (int) strtol (optarg, &tmp, 0); + if (*tmp || root_dir_entries < 16 || root_dir_entries > 32768) + { + printf ("Bad number of root directory entries : %s\n", optarg); + usage (); + } + break; + + case 'R': /* R : number of reserved sectors */ + reserved_sectors = (int) strtol (optarg, &tmp, 0); + if (*tmp || reserved_sectors < 1 || reserved_sectors > 0xffff) + { + printf ("Bad number of reserved sectors : %s\n", optarg); + usage (); + } + break; + + case 's': /* s : Sectors per cluster */ + sectors_per_cluster = (int) strtol (optarg, &tmp, 0); + if (*tmp || (sectors_per_cluster != 1 && sectors_per_cluster != 2 + && sectors_per_cluster != 4 && sectors_per_cluster != 8 + && sectors_per_cluster != 16 && sectors_per_cluster != 32 + && sectors_per_cluster != 64 && sectors_per_cluster != 128)) + { + printf ("Bad number of sectors per cluster : %s\n", optarg); + usage (); + } + break; + + case 'S': /* S : Sector size */ + sector_size = (int) strtol (optarg, &tmp, 0); + if (*tmp || (sector_size != 512 && sector_size != 1024 && + sector_size != 2048 && sector_size != 4096 && + sector_size != 8192 && sector_size != 16384 && + sector_size != 32768)) + { + printf ("Bad logical sector size : %s\n", optarg); + usage (); + } + sector_size_set = 1; + break; + + case 'v': /* v : Verbose execution */ + ++verbose; + break; + + default: + printf( "Unknown option: %c\n", c ); + usage (); + } + if (optind < argc) + { + device_name = argv[optind]; /* Determine the number of blocks in the FS */ + + if (!device_name) { + printf("No device specified.\n"); + usage(); + } + + if (!create) + cblocks = count_blocks (device_name); /* Have a look and see! */ + } + if (optind == argc - 2) /* Either check the user specified number */ + { + blocks = strtoull (argv[optind + 1], &tmp, 0); + if (!create && blocks != cblocks) + { + fprintf (stderr, "Warning: block count mismatch: "); + fprintf (stderr, "found %llu but assuming %llu.\n",cblocks,blocks); + } + } + else if (optind == argc - 1) /* Or use value found */ + { + if (create) + die( "Need intended size with -C." ); + blocks = cblocks; + tmp = ""; + } + else + { + fprintf (stderr, "No device specified!\n"); + usage (); + } + if (*tmp) + { + printf ("Bad block count : %s\n", argv[optind + 1]); + usage (); + } + + if (check && listfile) /* Auto and specified bad block handling are mutually */ + die ("-c and -l are incompatible"); /* exclusive of each other! */ + + if (!create) { + check_mount (device_name); /* Is the device already mounted? */ + dev = open (device_name, O_EXCL|O_RDWR); /* Is it a suitable device to build the FS on? */ + if (dev < 0) + die ("unable to open %s"); + } + else { + off_t offset = blocks*BLOCK_SIZE - 1; + char null = 0; + /* create the file */ + dev = open( device_name, O_EXCL|O_RDWR|O_CREAT|O_TRUNC, 0666 ); + if (dev < 0) + die("unable to create %s"); + /* seek to the intended end-1, and write one byte. this creates a + * sparse-as-possible file of appropriate size. */ + if (llseek( dev, offset, SEEK_SET ) != offset) + die( "seek failed" ); + if (write( dev, &null, 1 ) < 0) + die( "write failed" ); + if (llseek( dev, 0, SEEK_SET ) != 0) + die( "seek failed" ); + } + + if (fstat (dev, &statbuf) < 0) + die ("unable to stat %s"); + if (!S_ISBLK (statbuf.st_mode)) { + statbuf.st_rdev = 0; + check = 0; + } + else + /* + * Ignore any 'full' fixed disk devices, if -I is not given. + * On a MO-disk one doesn't need partitions. The filesytem can go + * directly to the whole disk. Under other OSes this is known as + * the 'superfloppy' format. As I don't know how to find out if + * this is a MO disk I introduce a -I (ignore) switch. -Joey + */ + if (!ignore_full_disk && ( + (statbuf.st_rdev & 0xff3f) == 0x0300 || /* hda, hdb */ + (statbuf.st_rdev & 0xff0f) == 0x0800 || /* sd */ + (statbuf.st_rdev & 0xff3f) == 0x0d00 || /* xd */ + (statbuf.st_rdev & 0xff3f) == 0x1600 ) /* hdc, hdd */ + ) + die ("Device partition expected, not making filesystem on entire device '%s' (use -I to override)"); + + if (sector_size_set) + { + if (ioctl(dev, BLKSSZGET, &min_sector_size) >= 0) + if (sector_size < min_sector_size) + { + sector_size = min_sector_size; + fprintf(stderr, "Warning: sector size was set to %d (minimal for this device)\n", sector_size); + } + } + else + { + if (ioctl(dev, BLKSSZGET, &min_sector_size) >= 0) + { + sector_size = min_sector_size; + sector_size_set = 1; + } + } + + if (sector_size > 4096) + fprintf(stderr, + "Warning: sector size is set to %d > 4096, such filesystem will not propably mount\n", + sector_size); + + establish_params (statbuf.st_rdev,statbuf.st_size); + /* Establish the media parameters */ + + setup_tables (); /* Establish the file system tables */ + + if (check) /* Determine any bad block locations and mark them */ + check_blocks (); + else if (listfile) + get_list_blocks (listfile); + + write_tables (); /* Write the file system tables away! */ + + exit (0); /* Terminate with no errors! */ +} + + +/* That's All Folks */ +/* Local Variables: */ +/* tab-width: 8 */ +/* End: */ diff --git a/src/version.h b/src/version.h new file mode 100644 index 0000000..5a97926 --- /dev/null +++ b/src/version.h @@ -0,0 +1,28 @@ +/* version.h + + Copyright (C) 1998-2005 Roman Hodek + + 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 3 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, see . + + On Debian systems, the complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + +#ifndef _version_h +#define _version_h + +#define VERSION "3.0.1" +#define VERSION_DATE "23 Nov 2008" + +#endif /* _version_h */ -- cgit v1.2.3