pax_global_header00006660000000000000000000000064134502150030014503gustar00rootroot0000000000000052 comment=178f742c030a05de70e06970adfa49672bf3a209 fstransform-0.9.4/000077500000000000000000000000001345021500300140615ustar00rootroot00000000000000fstransform-0.9.4/.gitignore000066400000000000000000000007111345021500300160500ustar00rootroot00000000000000*.o *~ Debug/ .deps/ .dirstamp /autom4te.cache/ /config.cache /config.log /config.status /Makefile /fsattr/build/Makefile /fsattr/build/fsattr /fsmount_kernel/build/Makefile /fsmount_kernel/build/fsmount_kernel /fsmove/build/Makefile /fsmove/build/fsmove /fsremap/build/Makefile /fsremap/build/fsremap /fsremap/src/config.hh /fsremap/src/ft_config.hh /fsremap/src/stamp-h1 /fstransform/build/Makefile /fstransform/build/fstransform /fstransform/fstransform fstransform-0.9.4/AUTHORS000066400000000000000000000001221345021500300151240ustar00rootroot00000000000000Author: Massimiliano Ghilardi Contributors: none yet... fstransform-0.9.4/COPYING000066400000000000000000001045131345021500300151200ustar00rootroot00000000000000 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 . fstransform-0.9.4/ChangeLog000066400000000000000000000125531345021500300156410ustar00rootroot00000000000000From 0.9.3 to 0.9.4, Massimiliano Ghilardi 2012-04-15: all: * testing IN PROGRESS on 'nilfs2' and 'ocfs2' file systems * some changes to compile on FreeBSD - still NOT finished! fsattr: * new program, used for fallocate() speedup on ext4 file system. it removes the 'fallocate' flag (actually named 'uninit') from all files inside an unmounted ext4 file system fsmove: * added option --io=prealloc to fallocate() target files instead of moving them from source to target. it's much faster and 100% safe, unlike default --io=posix that incrementally moves source files during work and cannot move them back in case of 'disk full' errors. fsremap: * UNFINISHED: added options --io=prealloc, --mount-point-device=DIR and --mount-point-loop-file=DIR used together with fsmove option --io=prealloc: in addition to the normal setup (i.e. scanning loop file and zero file) they assume target files (inside loop file) are preallocated and their contents still reside in the corresponding source files (inside device) * FIXME: support replaying preallocation From 0.9.2 to 0.9.3, Massimiliano Ghilardi 2012-03-27: fsremap: * added automatic checkpointing to persistence file * new option '--resume-job=NUMBER' to resume interrupted jobs from persistence file. works even if job was interrupted by power failure, kill -9, or similar catastrophic events * default directory for secondary storage and log files is now /var/tmp/fstransform/fsremap.job. to better conform with FHS * changed all options '--OPTION ARG' to '--OPTION=ARG' to conform with GNU guidelines * renamed option '--umount-cmd CMD' to '--cmd-umount=CMD' to use same convention as fstransform fstransform: * added cleanup in case of errors * now works also if device to transform is not mounted * default log file is now /var/tmp/fstransform/fstransform.log.$$ to better conform with FHS * added options '--list-source-file-systems' and '--list-target-file-systems' simplifies integration with other programs (gparted...) as they do not need to guess which file systems combinations are supported by fstransform From 0.9.1 to 0.9.2, Massimiliano Ghilardi 2012-03-08: all: * added explicit copyright statement to all source files fsmove: * added program description to '--help' output fsremap: * added check that last device block to be written is actually writeable. Reason: at least on Linux, if a filesystem is smaller than its containing device, it often limits to its own length the writable blocks in the device. * added program description to '--help' output fstransform: * renamed 'fstransform.sh' to 'fstransform' * added check that source and target file systems are among the tested ones: minix ext2 ext3 ext4 reiserfs jfs xfs * added options '--help' and '--force-untested-file-systems' From 0.9.0 to 0.9.1, Massimiliano Ghilardi 2012-02-13: fsremap: * fixed build errors on some Linux flavors (typically rpm-based ones) * fixed internal error on 32-bit platforms while remapping devices > 4GB fstransform: * option '--show-time' is now enabled by default, use '--show-time=no' to disable From 0.3.7 to 0.9.0, Massimiliano Ghilardi 2012-02-06: all: * replaced Eclipse-generated makefiles with automake+autoconf ones. new 'configure' script also autodetects required C functions, headers and types * added warning to README about transforming to 'xfs' a device more than 90% full fsmove: * added progress report and estimated time left fsremap: * zero-file is now optional. if not specified, fsremap performs an irreversible remapping fstransform: * added option '--show-time' to print time-of-day before each message * added option '--irreversible' to skip creating zero-file fstransform and fsremap: * added option '--no-questions' to run automatically without asking any confirmation. * added safety checks for devices with odd-sized last block: now fstransform creates a loop-file with length = device size _rounded_down_ to file-system block size, and fsremap refuses to run if loop-file length exceeds device size _rounded_down_ to file-system block size From 0.3.6 to 0.3.7, Massimiliano Ghilardi 2012-01-21: fsremap: * fixed a bug in the routine to show progress percentage. This bug cause fsremap to crash while remapping the device, leaving your data UNUSABLE. For this reason, PLEASE DO NOT USE FSTRANSFORM VERSION 0.3.6 From 0.2.8 to 0.3.6, Massimiliano Ghilardi 2012-01-21: fsmove: * added periodic checks for enough free space in both the source and target file-systems fsremap: * improved the routine to show progress percentage This routine was found to be bugged and crash while remapping the device, leaving your data UNUSABLE. For this reason, PLEASE DO NOT USE FSTRANSFORM VERSION 0.3.6 * added check and workaround for device lengths not multiples of block size * added check and workaround for incomplete information sometimes returned by ioctl(FS_IOC_FIEMAP) fstransform: * added script 'fstransform.sh', it executes automatically all the steps needed to perform a full file-system transformation fstransform-0.9.4/INSTALL000066400000000000000000000003661345021500300151170ustar00rootroot00000000000000Installation Instructions fstransform is currently tested only on Linux. Building and installing it is usually quite simple. Just run the following commands: ./configure make to actually install it, run as root the command make install fstransform-0.9.4/Makefile.am000066400000000000000000000002621345021500300161150ustar00rootroot00000000000000SUBDIRS = fsattr/build fsmove/build fsmount_kernel/build fsremap/build fstransform/build mrproper-distclean: distclean rm -fr autom4te.cache configure fsremap/src/ft_config.hh fstransform-0.9.4/Makefile.in000066400000000000000000000610131345021500300161270ustar00rootroot00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/tools/ft_cxx_flags.m4 \ $(top_srcdir)/tools/ft_cxx_features.m4 \ $(top_srcdir)/tools/ft_cxx_unordered_map.m4 \ $(top_srcdir)/tools/ft_need_funcs.m4 \ $(top_srcdir)/tools/ft_need_libs.m4 \ $(top_srcdir)/tools/ft_output.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__configure_deps) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/fsremap/src/config.hh CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir distdir-am dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags CSCOPE = cscope DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in \ $(top_srcdir)/fsremap/src/config.hh.in \ $(top_srcdir)/tools/install-sh $(top_srcdir)/tools/missing \ AUTHORS COPYING ChangeLog INSTALL NEWS README TODO \ tools/depcomp tools/install-sh tools/missing DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LD_LIBCOM_ERR = @LD_LIBCOM_ERR@ LD_LIBEXT2FS = @LD_LIBEXT2FS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CXX = @ac_ct_CXX@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = fsattr/build fsmove/build fsmount_kernel/build fsremap/build fstransform/build all: all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): fsremap/src/config.hh: fsremap/src/stamp-h1 @test -f $@ || rm -f fsremap/src/stamp-h1 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) fsremap/src/stamp-h1 fsremap/src/stamp-h1: $(top_srcdir)/fsremap/src/config.hh.in $(top_builddir)/config.status @rm -f fsremap/src/stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status fsremap/src/config.hh $(top_srcdir)/fsremap/src/config.hh.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f fsremap/src/stamp-h1 touch $@ distclean-hdr: -rm -f fsremap/src/config.hh fsremap/src/stamp-h1 # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build/sub \ && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ distcheck distclean distclean-generic distclean-hdr \ distclean-tags distcleancheck distdir distuninstallcheck dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs installdirs-am \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am .PRECIOUS: Makefile mrproper-distclean: distclean rm -fr autom4te.cache configure fsremap/src/ft_config.hh # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: fstransform-0.9.4/NEWS000066400000000000000000000000001345021500300145460ustar00rootroot00000000000000fstransform-0.9.4/README000066400000000000000000000247041345021500300147500ustar00rootroot00000000000000############################################################### ############################################################### ### ### DISCLAIMER ### ### THIS DOCUMENT EXPLAINS HOW TO USE ### RISKY PROGRAMS AND PROCEDURES ### THAT MAY COMPLETELY AND IRREVERSIBLY DELETE ### ALL THE DATA ON YOUR DISKS ### ### THE AUTHOR DECLINES ALL RESPONSIBILITIES ### FOR ANY DAMAGE THAT MAY DERIVE ### FROM USING THE PROGRAMS AND PROCEDURES ### DESCRIBED IN THIS DOCUMENT ### ############################################################### ############################################################### This document explains how use the programs 'fstransform', 'fsmove', 'fsmount_kernel' and 'fsremap' to transform the contents of a Linux device - usually a disk partition - from a filesystem type to another while preserving its contents. For example, a disk partition can be transformed from 'jfs' to 'ext4', or from 'ext2' to 'xfs', or many other combinations. Currently, the programs mentioned above have been tested on Linux with the following filesystems, both as source and as target: ext2, ext3, ext4, jfs, reiserfs, xfs. Do NOT use these programs with other filesystems unless you are willing to LOSE your data. In particular, they do NOT (yet) support ntfs, msdos, vfat and exfat file systems. Common sense and experience tell that you should ALWAYS have a backup of your valuable data: while the programs do NOT need to backup your data to operate, YOU need a backup in case something goes wrong. The programs have been tested carefully, yet there is ALWAYS a possibility that they will irreversibly delete ALL the data on the device you run them on, even if you use a tested combination of filesystems. All this foreword means only one thing: IF YOU LOSE YOUR DATA, IT IS YOUR PROBLEM. The author declines ALL responsibilities for ANY damage that may derive from using the programs and procedures described in this document. ############################################################### ############################################################### ### Introduction Enough legalese... now let's get to the interesting part. The program 'fstransform' does the following: it takes a device with a filesystem on it (even if almost full) and transforms the device to a different filesystem type, in-place (i.e. without backup) and non-destructively (i.e. it preserves all your data). It works even if the filesystem is almost full - several empyrical tests have succeeded even with a 95% full filesystem - and even if it contains very large files, for example if some files are larger than half the device or larger than the available space. ### REQUIREMENTS There are five requirements for fstransform to have a chance to succeed: 1. the device must be unmountable, i.e. `umount DEVICE` must work. In particular, if some running programs are using the device, you must first close or kill them. Transforming the current root directory does not work. For that, you should boot from a different installation (for example a live CD, DVD or USB). 2. the device must have a little free space, typically at least 5% WARNING: transforming an almost full device to 'xfs' file-system can be tricky: * you need either slightly more free space, typically at least 10%, * or you must be VERY quick at suspending fstransform when either the source or the target (or both) file-system is almost full and run 'xfs_fsr' on the source or target device (or both) before resuming fstransform. A future fstransform version may automate this operation. 3. the filesystem on the device must support SPARSE FILES, i.e. files with holes (see for example http://en.wikipedia.org/wiki/Sparse_file for an explanation of what they are) and at least one of the two system calls "ioctl(FS_IOC_FIEMAP)" or "ioctl(FIBMAP)" (see the file Documentation/filesystems/fiemap.txt in any recent Linux kernel for an explanation, or search for the same file on Internet) ioctl(FIBMAP) is limited by design to 2G-1 blocks, which typically translates to 8TB - 4kB. To transform file systems equal or larger than 8TB, ioctl(FIEMAP) is required. 4. the initial and final filesystems must be supported by the Linux kernel (i.e. it must be able to mount them) and by the tools 'mkfs' and 'fsck' (i.e. it must be possible to create them and check them for errors). Support through FUSE (userspace) drivers is acceptable in theory, but there are currently no tested FUSE filesystems that can be converted reliably with fstransform. 5. the following programs must be available: the three custom-made programs 'fsmove', 'fsmount_kernel' 'fsremap' (distributed with the script) and several common Linux tools: which, expr, id, blockdev, losetup, mount, umount, mkdir, rmdir, rm, mkfifo, dd, sync, fsck, mkfs ### KNOWN LIMITATIONS 1) As stated above, at a certain step during the conversion, fstransform needs to unmount the device being transformed. For this reason, running fstransform on the device currently mounted as / (i.e. the root directory) fails. For the same reason, running fstransform on the device currently mounted as /usr, /home or /var or similar heavily-used directories is difficult, because quite often there are programs using those, which prevents them from being unmounted. 2) If the device contains a HUGE number of files with multiple hard links, fstransform will be very slow and consume a LOT of memory. Devices with more than one million files with multiple hard links can cause fstransform to crash with "out of memory" errors. 3) JFS file systems equal or larger than 8TB cannot be converted due to missing support for ioctl(FIEMAP) in the kernel: the fallback ioctl(FIBMAP) is limited by design to < 8TB (assuming 4k blocks) Also, ioctl(FIBMAP) must be called for _each_ block so the conversion will be a bit slower. 4) REISERFS file systems using format "3.5" (the default) and equal or larger than 2TB cannot be converted due to their maximum file size = 2TB - 4k: fstransform needs to create a sparse file as large as the device itself. REISERFS file systems using format "3.6" are immune to this problem. 5) for the same reason, a device cannot be converted _to_ REISERFS format "3.5" if it contains some files larger than 2TB - 4k. ### DETAILS TO KNOW If the original device is almost full, the program 'fsremap' will create a relatively small backup file ("secondary storage") inside the directory /var/tmp/fstransform. This secondary storage file will be at most as large as half your free RAM. You can pass the option '-s [k|M|G|T|P|E|Y|Z]' to the tool 'fsremap' in order manually set the secondary storage size, but please understand that using a too small secondary storage can slow down the procedure. To pass the same option to 'fstransform', you must execute something like fstransform --opts-fsremap='-s ' ### PROCEDURE 0. compile fsmove, fsmount_kernel and fsremap. Running "./configure" then "make" should suffice on any recent Linux machine, as long as g++ is installed. You will get three executables, fsmove and fsremap. They will be located at ./fsmove/build/fsmove ./fsmount_kernel/build/fsmount_kernel ./fsremap/build/fsremap You are suggested to either run "make install" or to copy them to a simpler path. Below, they will be referred as {fsmove}, {fsmount_kernel} and {fsremap} 1. OPTIONAL - CAN BE SKIPPED mount read-write the device you want to remap to a new file-system type mount {device} {device-mount-point} [your-options] if the device is already mounted, check that it is mounted read-write and that no process is using it. 2. decide the target file-system type. For some combinations of the initial and final filesystems it is not necessary to use 'fstransform', as the same result can be obtained with much simpler - and SAFER - tools. For example, an 'ext2' or 'ext3' filesystem can be transformed into 'ext3' or 'ext4' using the program 'tune2fs'. Explaining how to use 'tune2fs' is beyond the scope of this document, just read its man-page or search on the Internet for one of "convert Linux File System ext2 to ext3" "convert Linux File System ext2 to ext3" "convert Linux File System ext3 to ext4" But for most combinations, the only way is either to do a full backup + format + restore the data, or use 'fstransform' 3. execute the program fstransform {device} {target-file-system-type} 4. follow the instructions - the program will tell you what it is doing, and will also call 'fsmove' and 'fsremap' which show progress percentage and estimated time left. Note that 'fsmove' and 'fsremap' need approximately the same time to run, so if 'fsmove' tells you that it will need 2 hours, 'fsmove' will likely need a similar amount of time, for a total of 4 hours. In case there are errors, you can even try to fix them instead of aborting the execution (if you know what you are doing). 5. be PATIENT. Transforming a large device takes a LONG time... On a fairly fast disk, it takes about one minute per gigabyte. It means transforming 1000GB takes about 16 hours. Raid disks can be somewhat faster, and solid state disks (SSD) can be _much_ faster. 6) if something goes really wrong, check in /var/tmp/fstransform for the log files fstransform.log. and fsremap.job./fsremap.log they are ABSOLUTELY necessary if you want someone to analyze the problem - but unless you are very lucky you can forget about recovering your data... 7) if for some reason the execution is interrupted while 'fsremap' is running, for example due to a power failure, it is possible to resume it by running 'fsremap --resume-job= {device}'. Also, 'fsremap' will show at its startup the exact command line needed to resume its execution. The loop file created by fstransform must NEVER be as argument to 'fsremap --resume-job= {...}'. You would IRREVERSIBLY LOSE YOUR DATA! SOME REAL-WORLD TESTS 1) 1000GB encrypted disk, 52% full, ext2->ext4: SUCCESS, took 12 hours despite one system crash and two manual interruptions (CTRL+C) (Yes, I know ext2->ext4 can be done with tune2s, but I wanted to test fstransform) 2) 1540GB encrypted raid0 (3 disks), 56% full, ext2->ext4: SUCCESS, took 8 hours Good luck! Massimiliano Ghilardi fstransform-0.9.4/README.md000066400000000000000000000247041345021500300153470ustar00rootroot00000000000000############################################################### ############################################################### ### ### DISCLAIMER ### ### THIS DOCUMENT EXPLAINS HOW TO USE ### RISKY PROGRAMS AND PROCEDURES ### THAT MAY COMPLETELY AND IRREVERSIBLY DELETE ### ALL THE DATA ON YOUR DISKS ### ### THE AUTHOR DECLINES ALL RESPONSIBILITIES ### FOR ANY DAMAGE THAT MAY DERIVE ### FROM USING THE PROGRAMS AND PROCEDURES ### DESCRIBED IN THIS DOCUMENT ### ############################################################### ############################################################### This document explains how use the programs 'fstransform', 'fsmove', 'fsmount_kernel' and 'fsremap' to transform the contents of a Linux device - usually a disk partition - from a filesystem type to another while preserving its contents. For example, a disk partition can be transformed from 'jfs' to 'ext4', or from 'ext2' to 'xfs', or many other combinations. Currently, the programs mentioned above have been tested on Linux with the following filesystems, both as source and as target: ext2, ext3, ext4, jfs, reiserfs, xfs. Do NOT use these programs with other filesystems unless you are willing to LOSE your data. In particular, they do NOT (yet) support ntfs, msdos, vfat and exfat file systems. Common sense and experience tell that you should ALWAYS have a backup of your valuable data: while the programs do NOT need to backup your data to operate, YOU need a backup in case something goes wrong. The programs have been tested carefully, yet there is ALWAYS a possibility that they will irreversibly delete ALL the data on the device you run them on, even if you use a tested combination of filesystems. All this foreword means only one thing: IF YOU LOSE YOUR DATA, IT IS YOUR PROBLEM. The author declines ALL responsibilities for ANY damage that may derive from using the programs and procedures described in this document. ############################################################### ############################################################### ### Introduction Enough legalese... now let's get to the interesting part. The program 'fstransform' does the following: it takes a device with a filesystem on it (even if almost full) and transforms the device to a different filesystem type, in-place (i.e. without backup) and non-destructively (i.e. it preserves all your data). It works even if the filesystem is almost full - several empyrical tests have succeeded even with a 95% full filesystem - and even if it contains very large files, for example if some files are larger than half the device or larger than the available space. ### REQUIREMENTS There are five requirements for fstransform to have a chance to succeed: 1. the device must be unmountable, i.e. `umount DEVICE` must work. In particular, if some running programs are using the device, you must first close or kill them. Transforming the current root directory does not work. For that, you should boot from a different installation (for example a live CD, DVD or USB). 2. the device must have a little free space, typically at least 5% WARNING: transforming an almost full device to 'xfs' file-system can be tricky: * you need either slightly more free space, typically at least 10%, * or you must be VERY quick at suspending fstransform when either the source or the target (or both) file-system is almost full and run 'xfs_fsr' on the source or target device (or both) before resuming fstransform. A future fstransform version may automate this operation. 3. the filesystem on the device must support SPARSE FILES, i.e. files with holes (see for example http://en.wikipedia.org/wiki/Sparse_file for an explanation of what they are) and at least one of the two system calls "ioctl(FS_IOC_FIEMAP)" or "ioctl(FIBMAP)" (see the file Documentation/filesystems/fiemap.txt in any recent Linux kernel for an explanation, or search for the same file on Internet) ioctl(FIBMAP) is limited by design to 2G-1 blocks, which typically translates to 8TB - 4kB. To transform file systems equal or larger than 8TB, ioctl(FIEMAP) is required. 4. the initial and final filesystems must be supported by the Linux kernel (i.e. it must be able to mount them) and by the tools 'mkfs' and 'fsck' (i.e. it must be possible to create them and check them for errors). Support through FUSE (userspace) drivers is acceptable in theory, but there are currently no tested FUSE filesystems that can be converted reliably with fstransform. 5. the following programs must be available: the three custom-made programs 'fsmove', 'fsmount_kernel' 'fsremap' (distributed with the script) and several common Linux tools: which, expr, id, blockdev, losetup, mount, umount, mkdir, rmdir, rm, mkfifo, dd, sync, fsck, mkfs ### KNOWN LIMITATIONS 1) As stated above, at a certain step during the conversion, fstransform needs to unmount the device being transformed. For this reason, running fstransform on the device currently mounted as / (i.e. the root directory) fails. For the same reason, running fstransform on the device currently mounted as /usr, /home or /var or similar heavily-used directories is difficult, because quite often there are programs using those, which prevents them from being unmounted. 2) If the device contains a HUGE number of files with multiple hard links, fstransform will be very slow and consume a LOT of memory. Devices with more than one million files with multiple hard links can cause fstransform to crash with "out of memory" errors. 3) JFS file systems equal or larger than 8TB cannot be converted due to missing support for ioctl(FIEMAP) in the kernel: the fallback ioctl(FIBMAP) is limited by design to < 8TB (assuming 4k blocks) Also, ioctl(FIBMAP) must be called for _each_ block so the conversion will be a bit slower. 4) REISERFS file systems using format "3.5" (the default) and equal or larger than 2TB cannot be converted due to their maximum file size = 2TB - 4k: fstransform needs to create a sparse file as large as the device itself. REISERFS file systems using format "3.6" are immune to this problem. 5) for the same reason, a device cannot be converted _to_ REISERFS format "3.5" if it contains some files larger than 2TB - 4k. ### DETAILS TO KNOW If the original device is almost full, the program 'fsremap' will create a relatively small backup file ("secondary storage") inside the directory /var/tmp/fstransform. This secondary storage file will be at most as large as half your free RAM. You can pass the option '-s [k|M|G|T|P|E|Y|Z]' to the tool 'fsremap' in order manually set the secondary storage size, but please understand that using a too small secondary storage can slow down the procedure. To pass the same option to 'fstransform', you must execute something like fstransform --opts-fsremap='-s ' ### PROCEDURE 0. compile fsmove, fsmount_kernel and fsremap. Running "./configure" then "make" should suffice on any recent Linux machine, as long as g++ is installed. You will get three executables, fsmove and fsremap. They will be located at ./fsmove/build/fsmove ./fsmount_kernel/build/fsmount_kernel ./fsremap/build/fsremap You are suggested to either run "make install" or to copy them to a simpler path. Below, they will be referred as {fsmove}, {fsmount_kernel} and {fsremap} 1. OPTIONAL - CAN BE SKIPPED mount read-write the device you want to remap to a new file-system type mount {device} {device-mount-point} [your-options] if the device is already mounted, check that it is mounted read-write and that no process is using it. 2. decide the target file-system type. For some combinations of the initial and final filesystems it is not necessary to use 'fstransform', as the same result can be obtained with much simpler - and SAFER - tools. For example, an 'ext2' or 'ext3' filesystem can be transformed into 'ext3' or 'ext4' using the program 'tune2fs'. Explaining how to use 'tune2fs' is beyond the scope of this document, just read its man-page or search on the Internet for one of "convert Linux File System ext2 to ext3" "convert Linux File System ext2 to ext3" "convert Linux File System ext3 to ext4" But for most combinations, the only way is either to do a full backup + format + restore the data, or use 'fstransform' 3. execute the program fstransform {device} {target-file-system-type} 4. follow the instructions - the program will tell you what it is doing, and will also call 'fsmove' and 'fsremap' which show progress percentage and estimated time left. Note that 'fsmove' and 'fsremap' need approximately the same time to run, so if 'fsmove' tells you that it will need 2 hours, 'fsmove' will likely need a similar amount of time, for a total of 4 hours. In case there are errors, you can even try to fix them instead of aborting the execution (if you know what you are doing). 5. be PATIENT. Transforming a large device takes a LONG time... On a fairly fast disk, it takes about one minute per gigabyte. It means transforming 1000GB takes about 16 hours. Raid disks can be somewhat faster, and solid state disks (SSD) can be _much_ faster. 6) if something goes really wrong, check in /var/tmp/fstransform for the log files fstransform.log. and fsremap.job./fsremap.log they are ABSOLUTELY necessary if you want someone to analyze the problem - but unless you are very lucky you can forget about recovering your data... 7) if for some reason the execution is interrupted while 'fsremap' is running, for example due to a power failure, it is possible to resume it by running 'fsremap --resume-job= {device}'. Also, 'fsremap' will show at its startup the exact command line needed to resume its execution. The loop file created by fstransform must NEVER be as argument to 'fsremap --resume-job= {...}'. You would IRREVERSIBLY LOSE YOUR DATA! SOME REAL-WORLD TESTS 1) 1000GB encrypted disk, 52% full, ext2->ext4: SUCCESS, took 12 hours despite one system crash and two manual interruptions (CTRL+C) (Yes, I know ext2->ext4 can be done with tune2s, but I wanted to test fstransform) 2) 1540GB encrypted raid0 (3 disks), 56% full, ext2->ext4: SUCCESS, took 8 hours Good luck! Massimiliano Ghilardi fstransform-0.9.4/TODO000066400000000000000000000070251345021500300145550ustar00rootroot00000000000000TODO * fstransform: preserve filesystem LABEL and UUID. To collect them, run "lsblk -r -o maj:min,label,uuid" warning: special characters in label and uuid will be escaped as \xAB * all: test on more file systems nilfs: ok as target. as source it gets practically full very quickly, free space fluctuates between zero and 1GB while the GC works to avoid "disk full" errors. But it works :) ntfs: ntfs-3g is VERY slow both as source and target because it's userspace. it supports only UTF-8 filenames, not arbitrary bytes in the range 128-255. fsmove must check beforehand! use mount.ntfs option big_writes... enough or still too slow? logfs: as target: "mkfs -t logfs" does NOT accept option -q, fsmove and umount crash with kernel bugs (see tests/) others: btrfs, gfs, gfs2, hfs, jffs2, ocfs2, qnx4, qnx6, ubifs... not yet: tux3 * fstransform, fsmove: add fsremap-like persistence, i.e. the ability to resume a transformation after CTRL-C, power failure or similar interruptions * fsmove: use a larger buffer (1MB) to speed up backward copy. Worth it? beware of low free space... * fsremap: add a graphical interface ? probably not so worth it... * all: port to FreeBSD. see this: Procedure to mount file system images under FreeBSD First you have to create virtual device, using this command: # mdconfig -a -t vnode -f /path/to/image.iso -u 1 The "mdconfig" command creates a device and prints the name. Just append that to "/dev/" and use it for whatever you need: # newfs /dev/md1 # mount /dev/md1 /mnt To unmount the image use command: # umount /mnt Once unmounted, you can unconfigure the device with # mdconfig -d -u 1 Also, many system files, as /lib/libc.so.7 are set as 'simmutable' (cannot open O_RDWR) and 'sunlink' (cannot unlink) so fsmove fails Furthermore, fsmove df-like stats do not work on FreeBSD: they seem to report usage of root file system Additionally, fsremap wraps calls to ff_posix_mkdir() with #ifdef __USE_POSIX, which is undefined by default on FreeBSD, causing ff_mkdir() to fail with ENOSYS. Finally, 'umount' wants mount-point instead of device. And how to 'mount -o remount,ro ' ? WONTDO * fsmove: if file system free space is critically low, launch 'xfs_fsr' to try and free some space before giving up. why not: LIMITED USEFULNESS: only for 'xfs' file system DANGEROUS: at least on linux with an almost-full source device xfs_fsr can WORSEN the problem by triggering 'loop write error' kernel errors, which mean the source device has not enough space to accommodate the loop file contents. typically this CORRUPTS the file system inside target (loop) device! DONE in 0.9.3 * all: check FHS (Filesystem Hierarchy Standard) and decide where to put persistence data. decision: /var/tmp/fstransform/ * fsremap: add persistence, i.e. the ability to resume a transformation after CTRL-C, power failure or similar interruptions * fstransform: also allow device to be UNMOUNTED instead of MOUNTED. gives easier integration with gparted, and guarantees that nobody is accessing the file-system inside device DONE in 0.9.2 * fsremap: preemptively check that last device block is writable. avoids troubles on linux with file-systems significantly smaller than device fstransform-0.9.4/acinclude.m4000066400000000000000000000003411345021500300162500ustar00rootroot00000000000000m4_include([tools/ft_cxx_flags.m4]) m4_include([tools/ft_cxx_features.m4]) m4_include([tools/ft_cxx_unordered_map.m4]) m4_include([tools/ft_need_funcs.m4]) m4_include([tools/ft_need_libs.m4]) m4_include([tools/ft_output.m4]) fstransform-0.9.4/aclocal.m4000066400000000000000000001165541345021500300157350ustar00rootroot00000000000000# generated automatically by aclocal 1.16.1 -*- Autoconf -*- # Copyright (C) 1996-2018 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # Copyright (C) 2002-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.16' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.16.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.16.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. AS_CASE([$CONFIG_FILES], [*\'*], [eval set x "$CONFIG_FILES"], [*], [set x $CONFIG_FILES]) shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`AS_DIRNAME(["$am_mf"])` am_filepart=`AS_BASENAME(["$am_mf"])` AM_RUN_LOG([cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles]) || am_rc=$? done if test $am_rc -ne 0; then AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments for automatic dependency tracking. Try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking).]) fi AS_UNSET([am_dirpart]) AS_UNSET([am_filepart]) AS_UNSET([am_mf]) AS_UNSET([am_rc]) rm -f conftest-deps.mk } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking is enabled. # This creates each '.Po' and '.Plo' makefile fragment that we'll need in # order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi dnl The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check whether make has an 'include' directive that can support all # the idioms we need for our automatic dependency tracking code. AC_DEFUN([AM_MAKE_INCLUDE], [AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) AS_CASE([$?:`cat confinc.out 2>/dev/null`], ['0:this is the am__doit target'], [AS_CASE([$s], [BSD], [am__include='.include' am__quote='"'], [am__include='include' am__quote=''])]) if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* AC_MSG_RESULT([${_am_result}]) AC_SUBST([am__include])]) AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 2001-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([acinclude.m4]) fstransform-0.9.4/configure000077500000000000000000006052741345021500300160060ustar00rootroot00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for fstransform 0.9.4. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and BUG-REPORT-ADDRESS $0: about your system, including any error possibly output $0: before this message. Then install a modern shell, or $0: manually run the script under such a shell if you do $0: have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='fstransform' PACKAGE_TARNAME='fstransform' PACKAGE_VERSION='0.9.4' PACKAGE_STRING='fstransform 0.9.4' PACKAGE_BUGREPORT='BUG-REPORT-ADDRESS' PACKAGE_URL='' ac_unique_file="fsremap/src/remap.cc" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_list= ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LD_LIBEXT2FS LD_LIBCOM_ERR LIBOBJS EGREP GREP CXXCPP am__fastdepCXX_FALSE am__fastdepCXX_TRUE CXXDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__include DEPDIR OBJEXT EXEEXT ac_ct_CXX CPPFLAGS LDFLAGS CXXFLAGS CXX AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL am__quote' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_dependency_tracking ' ac_precious_vars='build_alias host_alias target_alias CXX CXXFLAGS LDFLAGS LIBS CPPFLAGS CCC CXXCPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures fstransform 0.9.4 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/fstransform] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of fstransform 0.9.4:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build Some influential environment variables: CXX C++ compiler command CXXFLAGS C++ compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CXXCPP C++ preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF fstransform configure 0.9.4 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_cxx_try_cpp LINENO # ------------------------ # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_cpp # ac_fn_cxx_check_header_mongrel LINENO HEADER VAR INCLUDES # --------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_cxx_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## --------------------------------- ## ## Report this to BUG-REPORT-ADDRESS ## ## --------------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_cxx_check_header_mongrel # ac_fn_cxx_try_run LINENO # ------------------------ # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_cxx_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_run # ac_fn_cxx_check_header_compile LINENO HEADER VAR INCLUDES # --------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_cxx_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_cxx_check_header_compile # ac_fn_cxx_check_type LINENO TYPE VAR INCLUDES # --------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_cxx_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_cxx_check_type # ac_fn_c_find_uintX_t LINENO BITS VAR # ------------------------------------ # Finds an unsigned integer type with width BITS, setting cache variable VAR # accordingly. ac_fn_c_find_uintX_t () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 $as_echo_n "checking for uint$2_t... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" # Order is important - never check a type that is potentially smaller # than half of the expected target width. for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : case $ac_type in #( uint$2_t) : eval "$3=yes" ;; #( *) : eval "$3=\$ac_type" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if eval test \"x\$"$3"\" = x"no"; then : else break fi done fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_uintX_t # ac_fn_c_find_intX_t LINENO BITS VAR # ----------------------------------- # Finds a signed integer type with width BITS, setting cache variable VAR # accordingly. ac_fn_c_find_intX_t () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 $as_echo_n "checking for int$2_t... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" # Order is important - never check a type that is potentially smaller # than half of the expected target width. for ac_type in int$2_t 'int' 'long int' \ 'long long int' 'short int' 'signed char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default enum { N = $2 / 2 - 1 }; int main () { static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default enum { N = $2 / 2 - 1 }; int main () { static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else case $ac_type in #( int$2_t) : eval "$3=yes" ;; #( *) : eval "$3=\$ac_type" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if eval test \"x\$"$3"\" = x"no"; then : else break fi done fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_intX_t # ac_fn_cxx_check_member LINENO AGGR MEMBER VAR INCLUDES # ------------------------------------------------------ # Tries to find if the field MEMBER exists in type AGGR, after including # INCLUDES, setting cache variable VAR accordingly. ac_fn_cxx_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 $as_echo_n "checking for $2.$3... " >&6; } if eval \${$4+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : eval "$4=yes" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (sizeof ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : eval "$4=yes" else eval "$4=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$4 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_cxx_check_member # ac_fn_cxx_try_link LINENO # ------------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_link # ac_fn_cxx_check_func LINENO FUNC VAR # ------------------------------------ # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_cxx_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_cxx_check_func cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by fstransform $as_me 0.9.4, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi as_fn_append ac_header_list " stdlib.h" as_fn_append ac_header_list " unistd.h" as_fn_append ac_header_list " sys/param.h" # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers fsremap/src/config.hh" ac_aux_dir= for ac_dir in tools "$srcdir"/tools; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in tools \"$srcdir\"/tools" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. am__api_version='1.16' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='fstransform' VERSION='0.9.4' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 fi fi # Checks for programs. ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler works" >&5 $as_echo_n "checking whether the C++ compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C++ compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler default output file name" >&5 $as_echo_n "checking for C++ compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C++ compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if ${ac_cv_cxx_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if ${ac_cv_prog_cxx_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 $as_echo_n "checking whether ${MAKE-make} supports the include directive... " >&6; } cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } case $?:`cat confinc.out 2>/dev/null` in #( '0:this is the am__doit target') : case $s in #( BSD) : am__include='.include' am__quote='"' ;; #( *) : am__include='include' am__quote='' ;; esac ;; #( *) : ;; esac if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 $as_echo "${_am_result}" >&6; } # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CXX" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CXX_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CXX_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CXX_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CXX_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 $as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then am__fastdepCXX_TRUE= am__fastdepCXX_FALSE='#' else am__fastdepCXX_TRUE='#' am__fastdepCXX_FALSE= fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu # Checks for compiler characteristics { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -Wall" >&5 $as_echo_n "checking whether $CXX accepts -Wall... " >&6; } if ${ac_cv_cxx_flag_Wall+:} false; then : $as_echo_n "(cached) " >&6 else save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS -Wall" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return 0; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_cxx_flag_Wall=yes else ac_cv_cxx_flag_Wall=no CXXFLAGS="$save_CXXFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_flag_Wall" >&5 $as_echo "$ac_cv_cxx_flag_Wall" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -Wextra" >&5 $as_echo_n "checking whether $CXX accepts -Wextra... " >&6; } if ${ac_cv_cxx_flag_Wextra+:} false; then : $as_echo_n "(cached) " >&6 else save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS -Wextra" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return 0; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_cxx_flag_Wextra=yes else ac_cv_cxx_flag_Wextra=no CXXFLAGS="$save_CXXFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_flag_Wextra" >&5 $as_echo "$ac_cv_cxx_flag_Wextra" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -W" >&5 $as_echo_n "checking whether $CXX accepts -W... " >&6; } if ${ac_cv_cxx_flag_W+:} false; then : $as_echo_n "(cached) " >&6 else save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS -W" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return 0; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_cxx_flag_W=yes else ac_cv_cxx_flag_W=no CXXFLAGS="$save_CXXFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_flag_W" >&5 $as_echo "$ac_cv_cxx_flag_W" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -Wno-missing-field-initializers" >&5 $as_echo_n "checking whether $CXX accepts -Wno-missing-field-initializers... " >&6; } if ${ac_cv_cxx_flag_Wno_missing_field_initializers+:} false; then : $as_echo_n "(cached) " >&6 else save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS -Wno-missing-field-initializers" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return 0; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_cxx_flag_Wno_missing_field_initializers=yes else ac_cv_cxx_flag_Wno_missing_field_initializers=no CXXFLAGS="$save_CXXFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_flag_Wno_missing_field_initializers" >&5 $as_echo "$ac_cv_cxx_flag_Wno_missing_field_initializers" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports explicit template instantiation" >&5 $as_echo_n "checking whether $CXX supports explicit template instantiation... " >&6; } if ${ac_cv_cxx_have_template_instantiation+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ template class ft_my_class { public: void apply(T *); }; template void ft_my_class::apply(T * arg) { } template class ft_my_class; int main () { ft_my_class dummy; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_cxx_have_template_instantiation=yes else ac_cv_cxx_have_template_instantiation=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_have_template_instantiation" >&5 $as_echo "$ac_cv_cxx_have_template_instantiation" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports inhibiting template instantiation" >&5 $as_echo_n "checking whether $CXX supports inhibiting template instantiation... " >&6; } if ${ac_cv_cxx_have_template_inhibition+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ template class ft_my_class { public: void apply(T *); }; extern template class ft_my_class; int main () { ft_my_class dummy; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_cxx_have_template_inhibition=yes else ac_cv_cxx_have_template_inhibition=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_have_template_inhibition" >&5 $as_echo "$ac_cv_cxx_have_template_inhibition" >&6; } if test "$ac_cv_cxx_have_template_instantiation" = yes -a "$ac_cv_cxx_have_template_inhibition" = yes; then $as_echo "#define HAVE_EXTERN_TEMPLATE 1" >>confdefs.h fi # Checks for header files. ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 $as_echo_n "checking how to run the C++ preprocessor... " >&6; } if test -z "$CXXCPP"; then if ${ac_cv_prog_CXXCPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CXXCPP needs to be expanded for CXXCPP in "$CXX -E" "/lib/cpp" do ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CXXCPP=$CXXCPP fi CXXCPP=$ac_cv_prog_CXXCPP else ac_cv_prog_CXXCPP=$CXXCPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 $as_echo "$CXXCPP" >&6; } ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_cxx_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_cxx_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in cerrno climits cmath cstdarg cstdio cstdlib cstring ctime \ errno.h limits.h math.h stdarg.h stdio.h stdlib.h string.h time.h \ dirent.h fcntl.h features.h stddef.h stdint.h \ ext2fs/ext2fs.h linux/fiemap.h linux/fs.h \ sys/disklabel.h sys/ioctl.h sys/mman.h sys/mount.h sys/stat.h \ sys/statvfs.h sys/time.h sys/types.h sys/wait.h \ termios.h time.h unistd.h utime.h \ tr1/unordered_map unordered_map zlib.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_cxx_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # Checks for typedefs, and structures ac_fn_cxx_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" if test "x$ac_cv_type_mode_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define mode_t int _ACEOF fi ac_fn_cxx_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" if test "x$ac_cv_type_off_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define off_t long int _ACEOF fi ac_fn_cxx_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" if test "x$ac_cv_type_pid_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define pid_t int _ACEOF fi ac_fn_cxx_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi ac_fn_cxx_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" if test "x$ac_cv_type_ssize_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define ssize_t int _ACEOF fi ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t" case $ac_cv_c_uint8_t in #( no|yes) ;; #( *) $as_echo "#define _UINT8_T 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define uint8_t $ac_cv_c_uint8_t _ACEOF ;; esac ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t" case $ac_cv_c_uint16_t in #( no|yes) ;; #( *) cat >>confdefs.h <<_ACEOF #define uint16_t $ac_cv_c_uint16_t _ACEOF ;; esac ac_fn_c_find_intX_t "$LINENO" "32" "ac_cv_c_int32_t" case $ac_cv_c_int32_t in #( no|yes) ;; #( *) cat >>confdefs.h <<_ACEOF #define int32_t $ac_cv_c_int32_t _ACEOF ;; esac ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t" case $ac_cv_c_uint32_t in #( no|yes) ;; #( *) $as_echo "#define _UINT32_T 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define uint32_t $ac_cv_c_uint32_t _ACEOF ;; esac ac_fn_c_find_uintX_t "$LINENO" "64" "ac_cv_c_uint64_t" case $ac_cv_c_uint64_t in #( no|yes) ;; #( *) $as_echo "#define _UINT64_T 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define uint64_t $ac_cv_c_uint64_t _ACEOF ;; esac ac_fn_cxx_check_type "$LINENO" "long long" "ac_cv_type_long_long" "$ac_includes_default" if test "x$ac_cv_type_long_long" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LONG_LONG 1 _ACEOF fi ac_fn_cxx_check_type "$LINENO" "unsigned long long" "ac_cv_type_unsigned_long_long" "$ac_includes_default" if test "x$ac_cv_type_unsigned_long_long" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UNSIGNED_LONG_LONG 1 _ACEOF fi ac_fn_cxx_check_member "$LINENO" "struct disklabel" "d_secsize" "ac_cv_member_struct_disklabel_d_secsize" "$ac_includes_default #ifdef HAVE_SYS_DISKLABEL_H #include #endif " if test "x$ac_cv_member_struct_disklabel_d_secsize" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_DISKLABEL_D_SECSIZE 1 _ACEOF fi ac_fn_cxx_check_member "$LINENO" "struct disklabel" "d_secperunit" "ac_cv_member_struct_disklabel_d_secperunit" "$ac_includes_default #ifdef HAVE_SYS_DISKLABEL_H #include #endif " if test "x$ac_cv_member_struct_disklabel_d_secperunit" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_DISKLABEL_D_SECPERUNIT 1 _ACEOF fi ac_fn_cxx_check_member "$LINENO" "struct stat" "st_rdev" "ac_cv_member_struct_stat_st_rdev" "$ac_includes_default" if test "x$ac_cv_member_struct_stat_st_rdev" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_RDEV 1 _ACEOF fi ac_fn_cxx_check_member "$LINENO" "struct stat" "st_atim.tv_nsec" "ac_cv_member_struct_stat_st_atim_tv_nsec" "$ac_includes_default" if test "x$ac_cv_member_struct_stat_st_atim_tv_nsec" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC 1 _ACEOF fi ac_fn_cxx_check_member "$LINENO" "struct stat" "st_mtim.tv_nsec" "ac_cv_member_struct_stat_st_mtim_tv_nsec" "$ac_includes_default" if test "x$ac_cv_member_struct_stat_st_mtim_tv_nsec" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1 _ACEOF fi ac_fn_cxx_check_member "$LINENO" "struct stat" "st_atimensec" "ac_cv_member_struct_stat_st_atimensec" "$ac_includes_default" if test "x$ac_cv_member_struct_stat_st_atimensec" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_ATIMENSEC 1 _ACEOF fi ac_fn_cxx_check_member "$LINENO" "struct stat" "st_mtimensec" "ac_cv_member_struct_stat_st_mtimensec" "$ac_includes_default" if test "x$ac_cv_member_struct_stat_st_mtimensec" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_MTIMENSEC 1 _ACEOF fi # Checks for C library functions. for ac_header in vfork.h do : ac_fn_cxx_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default" if test "x$ac_cv_header_vfork_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_VFORK_H 1 _ACEOF fi done for ac_func in fork vfork do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done if test "x$ac_cv_func_fork" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 $as_echo_n "checking for working fork... " >&6; } if ${ac_cv_func_fork_works+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_fork_works=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* By Ruediger Kuhlmann. */ return fork () < 0; ; return 0; } _ACEOF if ac_fn_cxx_try_run "$LINENO"; then : ac_cv_func_fork_works=yes else ac_cv_func_fork_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5 $as_echo "$ac_cv_func_fork_works" >&6; } else ac_cv_func_fork_works=$ac_cv_func_fork fi if test "x$ac_cv_func_fork_works" = xcross; then case $host in *-*-amigaos* | *-*-msdosdjgpp*) # Override, as these systems have only a dummy fork() stub ac_cv_func_fork_works=no ;; *) ac_cv_func_fork_works=yes ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 $as_echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} fi ac_cv_func_vfork_works=$ac_cv_func_vfork if test "x$ac_cv_func_vfork" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 $as_echo_n "checking for working vfork... " >&6; } if ${ac_cv_func_vfork_works+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_vfork_works=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Thanks to Paul Eggert for this test. */ $ac_includes_default #include #ifdef HAVE_VFORK_H # include #endif /* On some sparc systems, changes by the child to local and incoming argument registers are propagated back to the parent. The compiler is told about this with #include , but some compilers (e.g. gcc -O) don't grok . Test for this by using a static variable whose address is put into a register that is clobbered by the vfork. */ static void #ifdef __cplusplus sparc_address_test (int arg) # else sparc_address_test (arg) int arg; #endif { static pid_t child; if (!child) { child = vfork (); if (child < 0) { perror ("vfork"); _exit(2); } if (!child) { arg = getpid(); write(-1, "", 0); _exit (arg); } } } int main () { pid_t parent = getpid (); pid_t child; sparc_address_test (0); child = vfork (); if (child == 0) { /* Here is another test for sparc vfork register problems. This test uses lots of local variables, at least as many local variables as main has allocated so far including compiler temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should reuse the register of parent for one of the local variables, since it will think that parent can't possibly be used any more in this routine. Assigning to the local variable will thus munge parent in the parent process. */ pid_t p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); /* Convince the compiler that p..p7 are live; otherwise, it might use the same hardware register for all 8 local variables. */ if (p != p1 || p != p2 || p != p3 || p != p4 || p != p5 || p != p6 || p != p7) _exit(1); /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent from child file descriptors. If the child closes a descriptor before it execs or exits, this munges the parent's descriptor as well. Test for this by closing stdout in the child. */ _exit(close(fileno(stdout)) != 0); } else { int status; struct stat st; while (wait(&status) != child) ; return ( /* Was there some problem with vforking? */ child < 0 /* Did the child fail? (This shouldn't happen.) */ || status /* Did the vfork/compiler bug occur? */ || parent != getpid() /* Did the file descriptor bug occur? */ || fstat(fileno(stdout), &st) != 0 ); } } _ACEOF if ac_fn_cxx_try_run "$LINENO"; then : ac_cv_func_vfork_works=yes else ac_cv_func_vfork_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5 $as_echo "$ac_cv_func_vfork_works" >&6; } fi; if test "x$ac_cv_func_fork_works" = xcross; then ac_cv_func_vfork_works=$ac_cv_func_vfork { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 $as_echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} fi if test "x$ac_cv_func_vfork_works" = xyes; then $as_echo "#define HAVE_WORKING_VFORK 1" >>confdefs.h else $as_echo "#define vfork fork" >>confdefs.h fi if test "x$ac_cv_func_fork_works" = xyes; then $as_echo "#define HAVE_WORKING_FORK 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lstat correctly handles trailing slash" >&5 $as_echo_n "checking whether lstat correctly handles trailing slash... " >&6; } if ${ac_cv_func_lstat_dereferences_slashed_symlink+:} false; then : $as_echo_n "(cached) " >&6 else rm -f conftest.sym conftest.file echo >conftest.file if test "$as_ln_s" = "ln -s" && ln -s conftest.file conftest.sym; then if test "$cross_compiling" = yes; then : ac_cv_func_lstat_dereferences_slashed_symlink=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { struct stat sbuf; /* Linux will dereference the symlink and fail, as required by POSIX. That is better in the sense that it means we will not have to compile and use the lstat wrapper. */ return lstat ("conftest.sym/", &sbuf) == 0; ; return 0; } _ACEOF if ac_fn_cxx_try_run "$LINENO"; then : ac_cv_func_lstat_dereferences_slashed_symlink=yes else ac_cv_func_lstat_dereferences_slashed_symlink=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi else # If the `ln -s' command failed, then we probably don't even # have an lstat function. ac_cv_func_lstat_dereferences_slashed_symlink=no fi rm -f conftest.sym conftest.file fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_lstat_dereferences_slashed_symlink" >&5 $as_echo "$ac_cv_func_lstat_dereferences_slashed_symlink" >&6; } test $ac_cv_func_lstat_dereferences_slashed_symlink = yes && cat >>confdefs.h <<_ACEOF #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 _ACEOF if test "x$ac_cv_func_lstat_dereferences_slashed_symlink" = xno; then case " $LIBOBJS " in *" lstat.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS lstat.$ac_objext" ;; esac fi for ac_header in stdlib.h do : ac_fn_cxx_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STDLIB_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 $as_echo_n "checking for GNU libc compatible malloc... " >&6; } if ${ac_cv_func_malloc_0_nonnull+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_malloc_0_nonnull=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined STDC_HEADERS || defined HAVE_STDLIB_H # include #else char *malloc (); #endif int main () { return ! malloc (0); ; return 0; } _ACEOF if ac_fn_cxx_try_run "$LINENO"; then : ac_cv_func_malloc_0_nonnull=yes else ac_cv_func_malloc_0_nonnull=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 $as_echo "$ac_cv_func_malloc_0_nonnull" >&6; } if test $ac_cv_func_malloc_0_nonnull = yes; then : $as_echo "#define HAVE_MALLOC 1" >>confdefs.h else $as_echo "#define HAVE_MALLOC 0" >>confdefs.h case " $LIBOBJS " in *" malloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS malloc.$ac_objext" ;; esac $as_echo "#define malloc rpl_malloc" >>confdefs.h fi for ac_header in $ac_header_list do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_cxx_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in getpagesize do : ac_fn_cxx_check_func "$LINENO" "getpagesize" "ac_cv_func_getpagesize" if test "x$ac_cv_func_getpagesize" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETPAGESIZE 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working mmap" >&5 $as_echo_n "checking for working mmap... " >&6; } if ${ac_cv_func_mmap_fixed_mapped+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_mmap_fixed_mapped=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default /* malloc might have been renamed as rpl_malloc. */ #undef malloc /* Thanks to Mike Haertel and Jim Avera for this test. Here is a matrix of mmap possibilities: mmap private not fixed mmap private fixed at somewhere currently unmapped mmap private fixed at somewhere already mapped mmap shared not fixed mmap shared fixed at somewhere currently unmapped mmap shared fixed at somewhere already mapped For private mappings, we should verify that changes cannot be read() back from the file, nor mmap's back from the file at a different address. (There have been systems where private was not correctly implemented like the infamous i386 svr4.0, and systems where the VM page cache was not coherent with the file system buffer cache like early versions of FreeBSD and possibly contemporary NetBSD.) For shared mappings, we should conversely verify that changes get propagated back to all the places they're supposed to be. Grep wants private fixed already mapped. The main things grep needs to know about mmap are: * does it exist and is it safe to write into the mmap'd area * how to use it (BSD variants) */ #include #include #if !defined STDC_HEADERS && !defined HAVE_STDLIB_H char *malloc (); #endif /* This mess was copied from the GNU getpagesize.h. */ #ifndef HAVE_GETPAGESIZE # ifdef _SC_PAGESIZE # define getpagesize() sysconf(_SC_PAGESIZE) # else /* no _SC_PAGESIZE */ # ifdef HAVE_SYS_PARAM_H # include # ifdef EXEC_PAGESIZE # define getpagesize() EXEC_PAGESIZE # else /* no EXEC_PAGESIZE */ # ifdef NBPG # define getpagesize() NBPG * CLSIZE # ifndef CLSIZE # define CLSIZE 1 # endif /* no CLSIZE */ # else /* no NBPG */ # ifdef NBPC # define getpagesize() NBPC # else /* no NBPC */ # ifdef PAGESIZE # define getpagesize() PAGESIZE # endif /* PAGESIZE */ # endif /* no NBPC */ # endif /* no NBPG */ # endif /* no EXEC_PAGESIZE */ # else /* no HAVE_SYS_PARAM_H */ # define getpagesize() 8192 /* punt totally */ # endif /* no HAVE_SYS_PARAM_H */ # endif /* no _SC_PAGESIZE */ #endif /* no HAVE_GETPAGESIZE */ int main () { char *data, *data2, *data3; const char *cdata2; int i, pagesize; int fd, fd2; pagesize = getpagesize (); /* First, make a file with some known garbage in it. */ data = (char *) malloc (pagesize); if (!data) return 1; for (i = 0; i < pagesize; ++i) *(data + i) = rand (); umask (0); fd = creat ("conftest.mmap", 0600); if (fd < 0) return 2; if (write (fd, data, pagesize) != pagesize) return 3; close (fd); /* Next, check that the tail of a page is zero-filled. File must have non-zero length, otherwise we risk SIGBUS for entire page. */ fd2 = open ("conftest.txt", O_RDWR | O_CREAT | O_TRUNC, 0600); if (fd2 < 0) return 4; cdata2 = ""; if (write (fd2, cdata2, 1) != 1) return 5; data2 = (char *) mmap (0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, 0L); if (data2 == MAP_FAILED) return 6; for (i = 0; i < pagesize; ++i) if (*(data2 + i)) return 7; close (fd2); if (munmap (data2, pagesize)) return 8; /* Next, try to mmap the file at a fixed address which already has something else allocated at it. If we can, also make sure that we see the same garbage. */ fd = open ("conftest.mmap", O_RDWR); if (fd < 0) return 9; if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fd, 0L)) return 10; for (i = 0; i < pagesize; ++i) if (*(data + i) != *(data2 + i)) return 11; /* Finally, make sure that changes to the mapped area do not percolate back to the file as seen by read(). (This is a bug on some variants of i386 svr4.0.) */ for (i = 0; i < pagesize; ++i) *(data2 + i) = *(data2 + i) + 1; data3 = (char *) malloc (pagesize); if (!data3) return 12; if (read (fd, data3, pagesize) != pagesize) return 13; for (i = 0; i < pagesize; ++i) if (*(data + i) != *(data3 + i)) return 14; close (fd); free (data); free (data3); return 0; } _ACEOF if ac_fn_cxx_try_run "$LINENO"; then : ac_cv_func_mmap_fixed_mapped=yes else ac_cv_func_mmap_fixed_mapped=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_fixed_mapped" >&5 $as_echo "$ac_cv_func_mmap_fixed_mapped" >&6; } if test $ac_cv_func_mmap_fixed_mapped = yes; then $as_echo "#define HAVE_MMAP 1" >>confdefs.h fi rm -f conftest.mmap conftest.txt for ac_func in execvp fallocate posix_fallocate fdatasync fileno fsync ftruncate \ getpagesize gettimeofday getuid lchown chown isatty localtime_r localtime \ memmove memset mkdir mkfifo mlock mount msync munmap random remove \ srandom strerror strftime sync sysconf time tzset utimes utimensat \ waitpid do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done # Checks for C++ library features. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ library implements std::unordered_map" >&5 $as_echo_n "checking whether C++ library implements std::unordered_map... " >&6; } if ${ac_cv_cxx_have_std_unordered_map+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_UNORDERED_MAP #include #endif int main () { std::unordered_map my_map; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_cxx_have_std_unordered_map=yes else ac_cv_cxx_have_std_unordered_map=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_have_std_unordered_map" >&5 $as_echo "$ac_cv_cxx_have_std_unordered_map" >&6; } if test "$ac_cv_cxx_have_std_unordered_map" = yes; then $as_echo "#define HAVE_STD_UNORDERED_MAP 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ library implements std::tr1::unordered_map" >&5 $as_echo_n "checking whether C++ library implements std::tr1::unordered_map... " >&6; } if ${ac_cv_cxx_have_std_tr1_unordered_map+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_TR1_UNORDERED_MAP #include #endif int main () { std::tr1::unordered_map my_map; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_cxx_have_std_tr1_unordered_map=yes else ac_cv_cxx_have_std_tr1_unordered_map=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_have_std_tr1_unordered_map" >&5 $as_echo "$ac_cv_cxx_have_std_tr1_unordered_map" >&6; } if test "$ac_cv_cxx_have_std_tr1_unordered_map" = yes; then $as_echo "#define HAVE_STD_TR1_UNORDERED_MAP 1" >>confdefs.h fi # Checks for libraries. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for error_message in -lcom_err" >&5 $as_echo_n "checking for error_message in -lcom_err... " >&6; } if ${ac_cv_lib_com_err_error_message+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcom_err $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char error_message (); int main () { return error_message (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_com_err_error_message=yes else ac_cv_lib_com_err_error_message=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_com_err_error_message" >&5 $as_echo "$ac_cv_lib_com_err_error_message" >&6; } if test "x$ac_cv_lib_com_err_error_message" = xyes; then : $as_echo "#define HAVE_LIBCOM_ERR 1" >>confdefs.h LD_LIBCOM_ERR=-lcom_err fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ext2fs_extent_replace in -lext2fs" >&5 $as_echo_n "checking for ext2fs_extent_replace in -lext2fs... " >&6; } if ${ac_cv_lib_ext2fs_ext2fs_extent_replace+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lext2fs $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char ext2fs_extent_replace (); int main () { return ext2fs_extent_replace (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_ext2fs_ext2fs_extent_replace=yes else ac_cv_lib_ext2fs_ext2fs_extent_replace=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ext2fs_ext2fs_extent_replace" >&5 $as_echo "$ac_cv_lib_ext2fs_ext2fs_extent_replace" >&6; } if test "x$ac_cv_lib_ext2fs_ext2fs_extent_replace" = xyes; then : $as_echo "#define HAVE_LIBEXT2FS 1" >>confdefs.h LD_LIBEXT2FS=-lext2fs fi ft_funcs_missing= for ft_func in execvp fileno ftruncate memmove memset mkdir mkfifo mount msync munmap \ remove strerror strftime sync time waitpid do : if test "`eval echo '$ac_cv_func_'$ft_func`" != "yes" then ft_funcs_missing="$ft_funcs_missing$ft_func " fi done if test "x$ft_funcs_missing" != "x" then as_fn_error $? "missing required functions: $ft_funcs_missing" fi ft_funcs_missing= ft_funcs_found= for ft_func in localtime_r localtime do : ft_funcs_missing="$ft_funcs_missing$ft_func " if test "`eval echo '$ac_cv_func_'$ft_func`" = "yes" then ft_funcs_found=1 fi done if test "x$ft_funcs_found" = "x" then as_fn_error $? "least one of the following functions is required: $ft_funcs_missing" fi ft_funcs_missing= ft_funcs_found= for ft_func in lchown chown do : ft_funcs_missing="$ft_funcs_missing$ft_func " if test "`eval echo '$ac_cv_func_'$ft_func`" = "yes" then ft_funcs_found=1 fi done if test "x$ft_funcs_found" = "x" then as_fn_error $? "least one of the following functions is required: $ft_funcs_missing" fi if test "$ac_cv_func_fallocate" != "yes" then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: missing function fallocate(), experimental files preallocation will NOT be compiled" >&5 $as_echo "$as_me: WARNING: missing function fallocate(), experimental files preallocation will NOT be compiled" >&2;} elif test "$ac_cv_lib_com_err_error_message" != "yes" then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: missing function error_message() in -lcom_err, experimental files preallocation will NOT be compiled" >&5 $as_echo "$as_me: WARNING: missing function error_message() in -lcom_err, experimental files preallocation will NOT be compiled" >&2;} elif test "$ac_cv_lib_ext2fs_ext2fs_extent_replace" != "yes" then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: missing function ext2fs_extent_replace() in -lext2fs, experimental files preallocation will NOT be compiled" >&5 $as_echo "$as_me: WARNING: missing function ext2fs_extent_replace() in -lext2fs, experimental files preallocation will NOT be compiled" >&2;} else $as_echo "#define HAVE_IO_PREALLOC 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: support for experimental files preallocation will be compiled" >&5 $as_echo "$as_me: support for experimental files preallocation will be compiled" >&6;} fi ac_config_files="$ac_config_files Makefile fsattr/build/Makefile fsremap/build/Makefile fsmove/build/Makefile fsmount_kernel/build/Makefile fstransform/build/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 $as_echo_n "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by fstransform $as_me 0.9.4, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ fstransform config.status 0.9.4 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "fsremap/src/config.hh") CONFIG_HEADERS="$CONFIG_HEADERS fsremap/src/config.hh" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "fsattr/build/Makefile") CONFIG_FILES="$CONFIG_FILES fsattr/build/Makefile" ;; "fsremap/build/Makefile") CONFIG_FILES="$CONFIG_FILES fsremap/build/Makefile" ;; "fsmove/build/Makefile") CONFIG_FILES="$CONFIG_FILES fsmove/build/Makefile" ;; "fsmount_kernel/build/Makefile") CONFIG_FILES="$CONFIG_FILES fsmount_kernel/build/Makefile" ;; "fstransform/build/Makefile") CONFIG_FILES="$CONFIG_FILES fstransform/build/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. case $CONFIG_FILES in #( *\'*) : eval set x "$CONFIG_FILES" ;; #( *) : set x $CONFIG_FILES ;; #( *) : ;; esac shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`$as_echo "$am_mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`$as_dirname -- "$am_mf" || $as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$am_mf" : 'X\(//\)[^/]' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$am_mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` am_filepart=`$as_basename -- "$am_mf" || $as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$am_mf" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` { echo "$as_me:$LINENO: cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles" >&5 (cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } || am_rc=$? done if test $am_rc -ne 0; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "Something went wrong bootstrapping makefile fragments for automatic dependency tracking. Try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking). See \`config.log' for more details" "$LINENO" 5; } fi { am_dirpart=; unset am_dirpart;} { am_filepart=; unset am_filepart;} { am_mf=; unset am_mf;} { am_rc=; unset am_rc;} rm -f conftest-deps.mk } ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi sed -e 's/define \([A-Z]\)/define FT_\1/g' -e 's/undef \([A-Z]\)/undef FT_\1/g' < fsremap/src/config.hh > fsremap/src/ft_config.hh fstransform-0.9.4/configure.ac000066400000000000000000000077551345021500300163650ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) AC_INIT([fstransform],[0.9.4],[BUG-REPORT-ADDRESS]) AC_CONFIG_SRCDIR([fsremap/src/remap.cc]) AC_CONFIG_HEADERS([fsremap/src/config.hh]) AC_CONFIG_AUX_DIR([tools]) AM_INIT_AUTOMAKE # Checks for programs. AC_PROG_CXX AC_PROG_INSTALL AC_LANG(C++) # Checks for compiler characteristics FT_CXX_FLAGS FT_CXX_FEATURES # Checks for header files. AC_CHECK_HEADERS([cerrno climits cmath cstdarg cstdio cstdlib cstring ctime \ errno.h limits.h math.h stdarg.h stdio.h stdlib.h string.h time.h \ dirent.h fcntl.h features.h stddef.h stdint.h \ ext2fs/ext2fs.h linux/fiemap.h linux/fs.h \ sys/disklabel.h sys/ioctl.h sys/mman.h sys/mount.h sys/stat.h \ sys/statvfs.h sys/time.h sys/types.h sys/wait.h \ termios.h time.h unistd.h utime.h \ tr1/unordered_map unordered_map zlib.h]) # Checks for typedefs, and structures AC_TYPE_MODE_T AC_TYPE_OFF_T AC_TYPE_PID_T AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_TYPE_UINT8_T AC_TYPE_UINT16_T AC_TYPE_INT32_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_CHECK_TYPES([long long]) AC_CHECK_TYPES([unsigned long long]) AC_CHECK_MEMBERS([struct disklabel.d_secsize, struct disklabel.d_secperunit], [], [], [AC_INCLUDES_DEFAULT [ #ifdef HAVE_SYS_DISKLABEL_H #include #endif]]) AC_CHECK_MEMBERS([struct stat.st_rdev, struct stat.st_atim.tv_nsec, struct stat.st_mtim.tv_nsec, struct stat.st_atimensec, struct stat.st_mtimensec]) # Checks for C library functions. AC_FUNC_FORK AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK AC_FUNC_MALLOC AC_FUNC_MMAP AC_CHECK_FUNCS([execvp fallocate posix_fallocate fdatasync fileno fsync ftruncate \ getpagesize gettimeofday getuid lchown chown isatty localtime_r localtime \ memmove memset mkdir mkfifo mlock mount msync munmap random remove \ srandom strerror strftime sync sysconf time tzset utimes utimensat \ waitpid]) # Checks for C++ library features. FT_CXX_STD_UNORDERED_MAP FT_CXX_STD_TR1_UNORDERED_MAP # Checks for libraries. AC_CHECK_LIB(com_err, error_message, [AC_DEFINE(HAVE_LIBCOM_ERR, 1, [Define to 1 if you have the com_err library.]) AC_SUBST(LD_LIBCOM_ERR, [-lcom_err])]) AC_CHECK_LIB(ext2fs, ext2fs_extent_replace, [AC_DEFINE(HAVE_LIBEXT2FS, 1, [Define to 1 if you have the ext2fs library.]) AC_SUBST(LD_LIBEXT2FS, [-lext2fs])]) dnl AC_CHECK_LIB(z, deflate, [AC_DEFINE(HAVE_Z_DEFLATE, 1, [Define to 1 if you have the z library.]) dnl AC_SUBST(LD_LIBZ, [-lz])]) FT_NEED_ALL_FUNCS([execvp fileno ftruncate memmove memset mkdir mkfifo mount msync munmap \ remove strerror strftime sync time waitpid]) FT_NEED_ANY_FUNC([localtime_r localtime]) FT_NEED_ANY_FUNC([lchown chown]) dnl FT_NEED_ALL_LIBS([com_err_error_message ext2fs_ext2fs_extent_replace]) dnl FT_NEED_ALL_LIBS([z_deflate]) if test "$ac_cv_func_fallocate" != "yes" then AC_MSG_WARN([missing function fallocate(), experimental files preallocation will NOT be compiled]) elif test "$ac_cv_lib_com_err_error_message" != "yes" then AC_MSG_WARN([missing function error_message() in -lcom_err, experimental files preallocation will NOT be compiled]) elif test "$ac_cv_lib_ext2fs_ext2fs_extent_replace" != "yes" then AC_MSG_WARN([missing function ext2fs_extent_replace() in -lext2fs, experimental files preallocation will NOT be compiled]) else AC_DEFINE(HAVE_IO_PREALLOC, 1, [Define to 1 if "prealloc" I/O is supported"]) AC_MSG_NOTICE([support for experimental files preallocation will be compiled]) fi AC_CONFIG_FILES([Makefile fsattr/build/Makefile fsremap/build/Makefile fsmove/build/Makefile fsmount_kernel/build/Makefile fstransform/build/Makefile]) AC_OUTPUT FT_OUTPUT fstransform-0.9.4/doc/000077500000000000000000000000001345021500300146265ustar00rootroot00000000000000fstransform-0.9.4/doc/README.fsremap000066400000000000000000000272141345021500300171500ustar00rootroot00000000000000############################################################################### ############################################################################### ############################################################################### ######### ######### ######### ######### ######### THIS DOCUMENT IS SUPERSEDED BY README.fstransform ######### ######### ######### ######### ######### ######### PLEASE SEE README.fstransform INSTEAD OF THIS FILE ######### ######### ######### ######### ######### ############################################################################### ############################################################################### ############################################################################### ############################################################################### ############################################################################### ############################################################################### ######### ######### ######### THIS DOCUMENT EXPLAINS HOW TO USE ######### ######### RISKY PROGRAMS AND PROCEDURES ######### ######### THAT MAY COMPLETELY AND IRREVERSIBLY RUIN ######### ######### THE DATA ON YOUR DISKS ######### ######### ######### ######### ######### ######### THE AUTHOR DECLINES ALL RESPONSIBILITIES ######### ######### FOR ANY DAMAGE THAT MAY DERIVE ######### ######### FROM USING THE PROGRAMS AND PROCEDURES ######### ######### DESCRIBED IN THIS DOCUMENT ######### ######### ######### ######### ######### ######### IF YOU CANNOT COMPLY ######### ######### WITH THE TERMS AND DISCLAIMERS STATED ABOVE, ######### ######### PLEASE STOP READING NOW ######### ######### AND DO NOT TRY TO USE THE PROGRAMS AND PROCEDURES ######### ######### EXPLAINED IN THIS DOCUMENT ######### ######### ######### ######### ######### ######### IF YOU KEEP READING, ######### ######### YOU MUST UNDERSTAND AND ACCEPT ALL THE RISKS ######### ######### BEFORE PROCEEDING ######### ######### ######### ############################################################################### ############################################################################### ############################################################################### This document explains how to manually use 'fsremap' and 'fsmove', bypassing the MUCH simpler and more user-friendly script 'fstransform.sh' It is useful only if a user does not want or cannot use the script 'fstransform.sh' for some reason, or for those folks that want to know the internal procedure used by 'fstransform.sh'. It explains which steps must be manually performed _as_root_ by a user, invoking existing tools (mount, umount, dd, losetup, mkfs.*, fsck.*) as well as 'fsremap' and 'fsmove', to convert a device from a filesystem to another, WITHOUT using 'fstransform.sh'. These steps are automated by 'fstransform.sh', but they are also kept here 1) for historical reasons 2) to document the internal procedure used by 'fstransform.sh' 3) in case 'fstransform.sh' cannot be used So, let's get started. FOREWORD: If the original device is almost full, the algorithm used by fsremap will create a backup file ("secondary storage", it will be up to half your free RAM) in your $HOME directory. You can use the option '-s [k|M|G|T|P|E|Y|Z]' to manually set the secondary storage size, but please understand that using a too small secondary storage can slow down fsremap. PROCEDURE: If you are still reading, let's see to how to actually use fsremap and fsmove: 0) compile them. Running "make" should suffice on any recent Linux machine, as long as g++ is installed. You will get two executables, fsmove and fsremap. They will be located at fstransform-{version}-src/fsmove/Release/fsmove and fstransform-{version}-src/fsremap/Release/fsmap You are suggested to either run "make install" or to copy them to a simpler path. Below, they will be referred as {fsmove} and {fsremap} 1) mount read-write the device you want to remap to a different file-system mount {device} {device-mount-point} [your-options] if the device is already mounted, check that it is mounted read-write and that no process is using it. 2) create a sparse file inside the device to be used as loop-file, with the same length as the device itself dd if=/dev/zero of={device-mount-point}/{loop-file} bs=1 count=1 seek=$(( {device-size-in-bytes} - 1 )) or, if you have truncate(1) truncate -s {device-size-in-bytes} {device-mount-point}/{loop-file} 3) format the loop-file with the new file system you want to use mkfs.[ext2,ext3,ext4,reiserfs,xfs,jfs...] {device-mount-point}/{loop-file} if you create an ext2/ext3/ext4 file-system, the option "-m 0" will help you to detect more precisely if/when the file-system inside the loop-file becomes full 4) mount the loop-file read-write mount {device-mount-point}/{loop-file} {loop-file-mount-point} -o loop {your-options} this will find a free /dev/loop{n}, setup it and mount it. if you have an old mount which does not understand "-o loop", you will need to manually find and setup a free loop-device: losetup /dev/loop{n} {device-mount-point}/{loop-file} [your-options] mount /dev/loop{n} {loop-file-mount-point} [your-options] 5) manually and recursively move all files, directories, links and so on from {device-mount-point} to {loop-file-mount-point}, reproducing inside {loop-file-mount-point} the original tree that was in {device-mount-point}. Quite obviously, you should not move {loop-file} itself. This part is the most delicate, because {loop-file} disk usage will grow while you copy files inside it, and {device} or /dev/loop{n} - or both - can become full: if it happens, you will be in BIG troubles. Let's see how to perform this delicate recursive move. You should have the fsmove program distributed with fstransform. If you have it in {fsmove}, run: {fsmove} {device-mount-point} {loop-file-mount-point} --exclude {device-mount-point}/{loop-file} ################## WARNING ####### WARNING ####### WARNING ################ The last command above can take a LONG time to complete, and it CAN fill either filesystem {device-mount-point} and/or {loop-file-mount-point}. Even if {fsmove} periodically checks for free space, you still MUST monitor its progress with something like watch df {device-mount-point} {loop-file-mount-point} because, if {device-mount-point} becomes full and the copy receives an 'I/O error', you are in trouble: the filesystem inside {loop-file-mount-point} will become CORRUPTED! So if you realize {device-mount-point} is going to become full, you MUST interrupt the copy BEFORE it happens (and give up, sorry). ######################## ALTERNATIVE SOLUTION ############################# If you don't have fsmove, things get a bit more ugly - and slow - and you need find(1), mv(1) and cpio(1) This is how: first recreate the directory tree inside loop-file with: ( cd {device-mount-point} && find -xdev -type d ) | cpio -o | ( cd {loop-file-mount-point} && cpio -i ) then move all the files one by one, except {loop-file} (note: {loop-file-mount-point} must be an absolute path) cd {device-mount-point} && find . -xdev \! -type d \! -path ./{loop-file} | while read i; do mv "$i" {loop-file-mount-point}/"$i" || break; done The same WARNING above still applies: you MUST monitor the free space on {device-mount-point} and {loop-file-mount-point} and interrupt the operation if you realize {device-mount-point} is going to become full. Actually, since these alternative commands do a simple file-by-file copy and do not check for free space, in this case it is even more critical to monitor the free space. 6) once all your files are inside the file-system in {loop-file}, things get less delicate. now you need to umount {loop-file}, 'sync' and check that {loop-file} is not corrupted umount {loop-file-mount-point} # if you used losetup before, you will need also: losetup -d /dev/loop{n} # then in any case continue with: sync fsck -f {device-mount-point}/{loop-file} you need to be ABSOLUTELY sure that there are no errors in the filesystem inside {device-mount-point}/{loop-file} before proceeding! Additionally, it is now the time to check that the kernel did not report any error while writing to {loop-file-mount-point}. Please run: dmesg and check that there are no recent I/O errors in the produced messages. 7) the initial setup is almost complete. now create a file full with zeros (not sparse) inside {device-mount-point} to help fsremap to locate any free disk space inside {device}: dd if=/dev/zero of={device-mount-point}/{zero-file} bs=512 the second command will exit with the error "no space left on device", but that's expected and not a problem. Note: if you have fallocate(1) and the file-system on {device} supports it, you can use fallocate instead of dd as it's much faster. 8) remount {device} read-only to be sure no process will write into it: mount {device} -o remount,ro 9) choose a folder with some free space (NOT inside {device}) where fsremap can write its (hopefully small) backup data and log files, and name it {storage-dir} If you skip this step, fsremap will use your home directory as default {storage-dir}. 10) start fsremap. If you have the executable in {fsremap}, run: {fsremap} -t {storage-dir} {device} {device-mount-point}/{loop-file} {device-mount-point}/{zero-file} if you did not choose a {storage-dir} folder, omit the arguments -t {storage-dir} and fsremap will use your home directory as default {storage-dir} if {device} has very little free space, fsremap will create a file {storage-dir}/.fsremap/job.{x}/storage.bin and use it to store blocks while moving them around. 11) after an analysis phase, fsremap will ask you to umount {device}. just do as asked: umount {device} 12) fsremap will now relocate blocks from {loop-file} to {device} and it will report its progress. once finished, check that the remapping actually worked: fsck -f {device} mount {device} {device-mount-point} [your-options] if everything worked, you can delete the file {storage-dir}/.fsremap/job.{x}/storage.bin in case of problems, you can post your problem to the mailing list, attaching the file {storage-dir}/.fsremap/job.{x}/fsremap.log and hopefully somebody will help diagnosing the problem... Good luck! fstransform-0.9.4/doc/design.txt000066400000000000000000000410711345021500300166430ustar00rootroot00000000000000fstransform idea comes from now-abandoned program convertfs (http://tzukanov.narod.ru/convertfs) and from the author's desire to return to C/C++ programming after a long hiatus. fstransform is designed and implemented from scratch with safety in mind: every reasonable precaution is taken in order not to lose/corrupt data. Anyway, the operations performed by fstransform, and especially the goal NOT to need or use a backup, are intrinsically VERY RISKY. For this reason, no matter how well (or badly) designed fstransform actually is, there are chances that by using it you will LOSE YOUR DATA. Please understand that the risk is only yours, and that you take full responsibility for using fstransform. In other words, the following standard disclaimer applies: THE AUTHOR DECLINES ALL RESPONSIBILITIES FOR ANY DAMAGE THAT MAY DERIVE FROM USING THE PROGRAMS AND PROCEDURES DESCRIBED IN THIS DOCUMENT Having said that, let's move to the requirements that led to fstransform: ############################### Requirements ################################## 1) be able function with very limited free disk space 2) be able to remap in-place a block device from any filesystem to any other, preserving file, directories, soft links, hard links, special devices, timestamps and owner/group permissions if the following prerequisites are satisfied: a) source filesystem supports sparse files (holes) and ioctl(FIEMAP or FIBMAP) b) both source and target filesystems are POSIX-like, i.e. they support links, special devices, timestamps and UNIX-like permissions 3) be reasonably fast operations on disk must be O(N), i.e. linear with device size, and perform large contiguous reads and writes as much as possible. #################### Requirements not yet implemented ######################## 4) be SAFE. If relevant hardware and drivers are working correctly, data must NEVER be lost or corrupted, not even in case of program crash or sudden power loss. Additionally, relevant hardware and drivers must be checked for known defects at program start, I/O problems must be detected as soon as possible, both using S.M.A.R.T. and by detecting I/O errors, and every reasonable effort must be made not to lose or corrupt data even in case of defective/failing disks or other relevant hardware and their drivers. 5) store work progress status on disk, and be able to resume work or completely undo it when program is started again. ################################# Reminders ################################### * instantiate template classes only T = ft_uint and T = ft_uoff * components must be emulable, especially OS I/O * fstatfs(loop_fd) to stat device file-system, including used space (=S) and total inodes (=I) * create loop file-system with number of inodes >= I * Immediately check on created loop file-system that available space >= S * move files inside loop file-system, monitoring available space on BOTH original device and loop file-system * at fsremap start, check that device is mounted read-only ############################## fsremap algorithm ################################# ================== Example initial situation ================= device +-----------------------------------------------------------------------------+ |01|02| |04| | |07|08| | | | | | |15| | | |19|20|21| | | | |26| +-----------------------------------------------------------------------------+ loop file inside device +-----------------------------------------------------------------------------+ | | | | |21|26| | |19|17|10|15|08|11| |07|09| | | | |02|01| |06| | +-----------------------------------------------------------------------------+ ============== Example final situation (target) ============== loop-file (physical blocks) +-----------------------------------------------------------------------------+ |01|02| | | |06|07|08|09|10|11| | | |15| |17| |19| |21| | | | |26| +-----------------------------------------------------------------------------+ device backup inside loop-file (physical blocks) - somewhere in these blocks +-----------------------------------------------------------------------------+ | | |**|**|**| | | | | | |**|**|**| |**| |**| |**| |**|**|**|**| | +-----------------------------------------------------------------------------+ ================ Algorithm simulation ================ 0) compute LOOP-FILE extents, DEVICE extents and FREE-SPACE extents 1) find LOOP-FILE (logical) holes, i.e. LOOP-HOLES +-----------------------------------------------------------------------------+ | | | | | | | | | | | | | | | | | | | | | | | | | | | +------03-04-05-------------------12-13-14----16----18----20----22-23-24-25---+ 2) re-number used DEVICE blocks, setting ->logical to values from loop-file holes (LOOP-HOLES). do not greedily use low hole numbers: a) prefer holes with ->logical numbers equal to DEVICE ->physical block number: they produce an INVARIANT block, already in its final destination (marked with @@) b) spread the remaining ->logical across rest of holes (use best-fit allocation) device renumbered blocks - original numbers are above +01-02----04-------07-08-------------------15----------19-20-21-------------26+ |03|05| |04| | |12|13| | | | | | |16| | | |18|20|23| | | | |25| +---------@@----------------------------------------------@@------------------+ 2.1) mark as INVARIANT (with @@) the LOOP-FILE (logical) blocks already in their final destination and forget them (no work on those). also compute total length of blocks remaining in LOOP-FILE. in this case, none +01-02----04-------07-08-------------------15----------19-20-21-------------26+ |03|05| |04| | |12|13| | | | | | |16| | | |18|20|23| | | | |25| +---------@@----------------------------------------------@@------------------+ 3) merge renumbered DEVICE blocks with remaining LOOP-FILE blocks (remember who's who) merged blocks +01-02----04-------07-08-------------------15----------19-20-21-------------26+ |03|05| |04|21|26|12|13|19|17|10|15|08|11|16|07|09| |18|20|23|02|01| |06|25| +---------@@----------------------------------------------@@------------------+ 4) compute (physical) intersection of FREE-SPACE and LOOP-HOLES, and mark it as INVARIANT FREE-SPACE (with !!). we can use these blocks as partial or total replacement for STORAGE - see 5) if there are sections with enough consecutive blocks (>= blocks to relocate / 1024) in this case, only 24 +01-02----04-------07-08-------------------15----------19-20-21-------------26+ |03|05| |04|21|26|12|13|19|17|10|15|08|11|16|07|09| |18|20|23|02|01| |06|25| +---------@@----------------------------------------------@@----------!!------+ 5) sort Favor in-order disk reads, even if they cause out-of-order disk writes Reason: exploit read-ahead and write-back to speed up execution Reads and writes will happen in moderately large in-order chunks, such that: a) chunk size must fit into RAM b) storage must not overflow storage is the contatenation of primary-storage and secondary-storage. primary-storage is the intersection of FREE-SPACE and LOOP-HOLES, aligned to system PAGE_SIZE. secondary storage is the file ${dir}/.fsremap/job.$$.storage +==============+ | | | | | | storage (SMALL!) +==============+ 5.0) start with position P=1 5.1) if storage has N free blocks (in this case N=5), lookup the contents of the consecutive positions P..P+N-1 on disk (in this case 01..05). 5.2) note the blocks in such positions (in this case 03|05| |04|21). ignore both free blocks and blocks already in their final destination: in case we find either kind, go back to 5.1 and increase N accordingly (in some cases we could loop between 5.1 and 5.2 many times) (in this case, one block is free and another - 04 - is in its final destination so we set N=7, extend the lookup to 01..07 and find 03|05| |@@|21|26|12 - again, remember to ignore 04, it's marked @@) 5.3) sort the found blocks by their (logical) number (in this case 03 05 12 21 26) 5.4) for each block, check the contents of its final destination (in this case, pos[03]=free, pos[05]=21, pos[12]=15, pos[21]=23, pos[26]=25). if a final destination is free, move the block there and mark its old position as free, otherwise put the block in a "move queue" 5.5) for each non-free final destination, examine the "lookup" block it contains and check if such block final destination is free or not. in case it is free, directly move there the "lookup" block, else move the "lookup" block into storage. also remember to update the "move queue", as some "lookup" blocks may also belong to it (in this case, final destinations are 21 15 23 25. none of them is free, so blocks 03 05 12 21 26 are moved to storage) +======21=26===+ |21|15|23|25| | storage +==============+ 5.6) mark as free the blocks moved away from final destinations checked at 5.4) +01-02----04-------07-08-------------------15----------19-20------------------+ |03|05| |04| |26|12|13|19|17|10| |08|11|16|07|09| |18|20| |02|01| |06| | +---------@@----------------------------!!----------------@@----!!----!!------+ 5.7) move blocks in the "move queue" to their final destinations, if they were not moved already to their final destination by step 5.5 (note: step 5.5 could have moved them to storage) remember to read and write them in disk order, and to mark their initial position as free AFTER they have been written in their final destination, and recorded as such. (in this case: read 03|05 21|26|12, write 03 05 12 21 26) and to mark them with @@ +------01-04-02-------08----------07-------15----------19-20------------------+ | | |03|04|05| | |13|19|17|10|12|08|11|16|07|09| |18|20|21|02|01| |06|26| +------@@-@@-@@-------------------@@----!!----------------@@-@@-!!----!!----@@+ 5.8) in storage, mark as free any block that was just written (to its final destination) during previous step (in this case, 21). +======21=26===+ | |15|23|25| | storage +==============+ 5.9) scan storage for blocks that can be directly written to their final destination (i.e. if it's free) and move them (in this case none) 5.10) if storage is at least 50% full then perform extra pass 6, else set P = P+N and restart from 5.1 if new P is less than device size 6) extra pass if storage is at least 50% full 6.1) find at least N/2 and up to N blocks that can be directly moved to their final destination note: since storage has at least N/2 blocks, there are at least N/2 free final destinations, and thus at least N/2 blocks that could be moved to such destinations. how to find: get the position number of free blocks not marked '!!' note: the blocks could be in storage if we arrived here from step 6.2) (in this case 01 02 06 07 18) read them in disk order (in this case 07 18 02 01 06) and write them into their final destination in disk order (in this case 01 02 07 07 18) +------01-04-02-------08----------07-------15-------19----20------------------+ |01|02|03|04|05|06|07|13|19|17|10|12|08|11|16| |09|18| |20|21| | | | |26| +@@-@@-@@-@@-@@-@@-@@-------------@@----!!----------@@----@@-@@-!!----!!----@@+ 6.2) repeat 6.1) until storage is 25% full or less, or until work is finished, or until less than N/2 blocks can be moved (whatever comes first) (in this case move 16 19 23 25) +------01-04-02-------08----------07----------15----19----20-------21----26---+ |01|02|03|04|05|06|07|13| |17|10|12|08|11| |16|09|18|19|20|21| |23| |25|26| +@@-@@-@@-@@-@@-@@-@@-------------@@----!!----@@----@@-@@-@@-@@-!!-@@-!!-@@-@@+ +==============+ | |15| | | | storage +==============+ 6.3) OBSOLETE - free positions marked as '!!' are primary-storage move as many blocks as possible from storage to free positions marked '!!' (in this case 15) +------01-04-02-------08----------07----------15----19----20-------21----26---+ |01|02|03|04|05|06|07|13| |17|10|12|08|11| |16|09|18|19|20|21|15|23| |25|26| +@@-@@-@@-@@-@@-@@-@@-------------@@----!!----@@----@@-@@-@@-@@-!!-@@-!!-@@-@@+ +==============+ | | | | | | storage +==============+ 6.4) set P = P + N and restart from 5.1 if new P is less than device size (in this case N = 7 and new P = 8) [continued] [5.1] N=5, lookup positions 08..12 [5.2] pos[09]=free, pos[12]=@@, so increase N=7 and try again [5.1] N=7, lookup positions 08..14, found blocks 13 17 10 08 11 (ignore 12, is marked '@@') [5.2] 5 positions are used (= storage size), continue with [5.3] [5.3] order blocks by their number, 08 10 11 13 17 [5.4] for each block, check the contents of its final destination pos[08]=13, pos[10]=17, pos[11]=10, pos[13]=08, pos[17]=09 read blocks in final destinations, 13 17 10 08 09 [5.5] check the contents of such blocks (13 17 10 08 09) final destinations. for each such block, in case its own final destination is free move it there, else move it into storage only 09 can be moved directly (17 requires 09 to be moved first, 13 requires 08 to be moved first), so put 13 17 10 08 to storage. +08============+ |13|17|10|08| | storage +==============+ [5.6] mark the blocks moved away from final destinations as free +------01-04-02-------------------07----------15----19----20-------21----26---+ |01|02|03|04|05|06|07| |09| | |12| |11| |16| |18|19|20|21|15|23| |25|26| +@@-@@-@@-@@-@@-@@-@@----@@-------@@----!!----@@----@@-@@-@@-@@-!!-@@-!!-@@-@@+ [5.7] move the blocks selected at step [5.2] into their final destinations, if they were not moved already in their final destination by step 5.5 (note: step 5.5 could have moved them to storage) read/write in disk order, update marks. read 13 17 10 08 11 (11 from main device, others from storage) write 08 10 11 13 17 to their final destinations +------01-04-02-------------------07-08-------15----19----20-------21----26---+ |01|02|03|04|05|06|07|08|09|10|11|12|13| | |16|17|18|19|20|21|15|23| |25|26| +@@-@@-@@-@@-@@-@@-@@-@@-@@-@@-@@-@@-@@-!!----@@-@@-@@-@@-@@-@@-!!-@@-!!-@@-@@+ [5.8] in storage, mark as free any block that was just written (to its final destination) during previous step (in this case, all). +==============+ | | | | | | storage +==============+ [5.9] scan storage for blocks that can be directly written to their final destination (i.e. if it's free) and move them (in this case none) [5.10] if storage is more than 50% full then perform extra pass 6, else set P = P+N and restart from 5.1 if new P is less than device size (in this case storage is empty, so since N=7, set new P=15 and restart from 5.1) [5.1] N=5, lookup positions 15..19 [5.2] pos[15]=free, all other = @@, so increase N=10 and try again [5.1] N=10, lookup positions 15..24 [5.2] ignoring free and @@ positions, we find pos[22] = 15 so increase N=14 and try again [5.1] N=14, lookup positions 15..28 -> truncate to device length (26) so N=12, lookup 15..26 [5.2] ignoring free and @@ positions, we still find only pos[22] = 15 and cannot increase N more, we are at end of device [5.3] order found blocks by their number, 15 [5.4] for each block, check the contents of its final destination pos[15]=free read blocks in final destinations, none [5.5] check the contents of such blocks (none) final destinations and for each such block -> empty loop [5.6] mark the blocks moved away from final destinations (none) as free [5.7] move the blocks selected at step [5.2] into their final destinations, if they were not moved already in their final destination by step 5.5 (note: step 5.5 could have moved them to storage) read/write in disk order, update marks. we move block 15 to its destination +------01-04-02-------------------07-08-------15----19----20-------21----26---+ |01|02|03|04|05|06|07|08|09|10|11|12|13| |15|16|17|18|19|20|21| |23| |25|26| +@@-@@-@@-@@-@@-@@-@@-@@-@@-@@-@@-@@-@@-!!-@@-@@-@@-@@-@@-@@-@@-!!-@@-!!-@@-@@+ [5.8] in storage, mark as free any block that was just written (to its final destination) during previous step (in this case, none). [5.9] scan storage for blocks that can be directly written to their final destination (i.e. if it's free) and move them (in this case none) [5.10] if storage is more than 50% full then perform extra pass 6, else set P = P+N and restart from 5.1 if new P is less than device size (in this case storage is empty, so since N=12, set new P=26, is not less than device size -> we finished) fstransform-0.9.4/doc/notes.txt000066400000000000000000000062551345021500300165270ustar00rootroot00000000000000############################################### ################### NOTES ##################### ############################################### 1) logging 1.1) ff_log() and ff_vlog() must check if log subsystem is not initialized, and in case initialize it. removes the need to manually call ff_log_init() 1.2) ff_log(err) must distinguish between unreported (not yet logged) and reported (already logged) errors. the former have normal sign (EINVAL, ENOMEM...) and are reported normally, the latter have opposite sign (-EINVAL, -ENOMEM...) and are reported as " (caused by previous error: %s)" 1.2.1) ff_log() and ff_vlog() always return errors as reported (-EINVAL, -ENOMEM...) 1.2.2) ft_remap.main() and other high-level *.main() methods must check for unreported errors and log them them with message "failed with unreported error" 1.3) configurable log format: FC_FMT_MSG, // message only FC_FMT_LEVEL_MSG, // level + message FC_FMT_DATETIME_LEVEL_MSG, // datetime + level + message FC_FMT_DATETIME_LEVEL_CALLER_MSG, // datetime + level + [file.func(line)] + message 1.4.1) -v enables FC_FMT_LEVEL_MSG also for stdout/stderr 1.4.2) -vv enables FC_FMT_DATETIME_LEVEL_MSG also for stdout/stderr 1.4.3) instead fsremap.log always uses FC_FMT_DATETIME_LEVEL_CALLER_MSG 1.5) more log(DEBUG) in io_posix.read_extents() 2) io.copy() and io.flush() queueing is managed by io, not its subclasses, Overflow checks must be performed by the queueing methods in io. 3) -n, --dry-run options to run everything normally (including which I/O to use), except that extents relocation does not read/write on disk problem: still create secondary storage? yes, but create it sparse 4) mlock(primary_storage). without it we get a lot of disk thrashing, but even with it disk I/O is not fully sequential. An alternative would be not to mmap() at all primary_storage, and maybe neither secondary_storage 5) fsremap must correctly handle the case where device_len and/or loop_file_len are not multiples of effective block size and file-system in loop_file uses a smaller block size than file-system in device PARTIALLY implemented: fstransform creates a loop_file that is always multiple of device block size. In this way, fsremap will not have problems. 6) some ioctl(FIEMAP) implementations are strange (buggy?) and refuse to return more than a certain number of extents (approx. 1300) in a single call. if this case happens, fsremap MUST detect that the returned extents are incomplete, log the problem, and work around it - currently, fsremap switches to ioctl(FIBMAP) if it happens. 7) fsmove MUST preemptively check for DISK ALMOST FULL conditions on {source-device} and {target-device} Checking for I/O errors during the copy is NOT enough: Linux loop devices created on top of sparse files (the case we exploit) do NOT report ANY error when writing to the backing sparse file fails because of disk full, but only write the I/O error to kernel messages (dmesg). ############################################### ################### TO DO ##################### ############################################### * bug? primary storage sometimes too small fstransform-0.9.4/doc/torture-test.sh000066400000000000000000000052411345021500300176450ustar00rootroot00000000000000# # This simple script is a helper to run torture tests on 'fstransform.sh' # # It is designed assuming the availability of certain files and commands # in certain hard-coded paths, # and it will NOT be useful for the general public until customized. # DEVICE_FILE_SAVE=0.device DEVICE_FILE=1.device LOOP_FILE=random DEVICE_MOUNT_POINT=device ZERO_FILE=zero FSREMAP=fsremap CAT_RANDOM=cat-random set -e set -x if [ "$1" = "" ]; then TESTDIR=torture-test.dir.0 else TESTDIR="$1" shift fi if [ "$1" = "" ]; then # this is a race condition if multiple torture-test.sh are executed simultaneously: # in such case you must specify explicitly which loop device to use DEVICE=`losetup -f` else DEVICE="$1" shift fi if [ "$1" = "" ]; then FILE_SIZE=16777216 else FILE_SIZE=`expr $1 / 4096 \* 4096` shift fi if [ "$#" = 0 ]; then MKFS="mkfs -t ext2" else MKFS="$@" fi DEVICE_SIZE=`expr $FILE_SIZE \* 11 / 10 / 4096 \* 4096` mkdir "$TESTDIR" || true mount -t tmpfs tmpfs "$TESTDIR" mkdir "$TESTDIR"/device pushd "$TESTDIR" exec >& log.txt cleanup() { set +e exec >& /dev/tty trap - EXIT SIGHUP SIGINT SIGQUIT SIGILL SIGTRAP SIGABRT SIGBUS SIGFPE SIGSEGV SIGALRM SIGTERM SIGSTKFLT echo 'press ENTER to delete test files and quit.' read dummy popd umount "$TESTDIR"/$DEVICE_MOUNT_POINT losetup -d "$DEVICE" umount "$TESTDIR" rmdir "$TESTDIR" exit 1 } trap cleanup EXIT SIGHUP SIGINT SIGQUIT SIGILL SIGTRAP SIGABRT SIGBUS SIGFPE SIGSEGV SIGALRM SIGTERM SIGSTKFLT $CAT_RANDOM $FILE_SIZE > $LOOP_FILE truncate -s $DEVICE_SIZE $LOOP_FILE while true; do rm -f $DEVICE_FILE truncate -s $DEVICE_SIZE $DEVICE_FILE losetup -d "$DEVICE" 2>/dev/null || true losetup "$DEVICE" $DEVICE_FILE $MKFS "$DEVICE" mount "$DEVICE" $DEVICE_MOUNT_POINT cp -avf --sparse=always $LOOP_FILE $DEVICE_MOUNT_POINT/ dd bs=512 if=/dev/zero of=$DEVICE_MOUNT_POINT/$ZERO_FILE 2>/dev/null || true # show $ZERO_FILE length stat --format=%s $DEVICE_MOUNT_POINT/$ZERO_FILE mount -o remount,ro "$DEVICE" sync cp -vf --sparse=always "$DEVICE" $DEVICE_FILE_SAVE $FSREMAP -t . -q "$DEVICE" $DEVICE_MOUNT_POINT/$LOOP_FILE $DEVICE_MOUNT_POINT/$ZERO_FILE < /dev/null umount "$DEVICE" || true if false; then if ! cmp "$DEVICE" $DEVICE_FILE; then echo "$DEVICE and $DEVICE_FILE differ!!! bug in Linux loop devices?" cmp -l "$DEVICE" $DEVICE_FILE | less break fi fi || true sync if ! losetup -d "$DEVICE"; then fuser -vm "$DEVICE" || true losetup -d "$DEVICE" fi if ! cmp $LOOP_FILE $DEVICE_FILE; then echo "$LOOP_FILE and $DEVICE_FILE differ!!! bug in fsremap?" cmp -l $LOOP_FILE $DEVICE_FILE | less break fi done exit 1 fstransform-0.9.4/examples/000077500000000000000000000000001345021500300156775ustar00rootroot00000000000000fstransform-0.9.4/examples/fsremap.job.1/000077500000000000000000000000001345021500300202445ustar00rootroot00000000000000fstransform-0.9.4/examples/fsremap.job.1/fsremap.log000066400000000000000000001032001345021500300224000ustar00rootroot000000000000002012-02-10 01:02:42 NOTICE [job.init(114)] fsremap: starting job 1 2012-02-10 01:02:42 INFO [job.init(115)] job persistent data and logs will be in '/root/.fstransform/fsremap.job.8' 2012-02-10 01:02:42 INFO [io/io_posix.open_dev(136)] device length is 6.00 gigabytes 2012-02-10 01:02:42 INFO [remap.run(605)] analyzing device '/dev/loop0', this may take some minutes ... 2012-02-10 01:02:42 DEBUG [io/extent_posix.ff_linux_fiemap(298)] ioctl(7, FS_IOC_FIEMAP, extents[99639]) succeeded 2012-02-10 01:02:42 INFO [io/io.read_extents(117)] device effective block size = 4096 2012-02-10 01:02:42 INFO [dispatch.main(29)] using reduced (32 bit) remapping algorithm 2012-02-10 01:02:42 DEBUG [work.show(63)] # 98286 extents in loop-file 2012-02-10 01:02:42 DEBUG [work.show(63)] # 259 extents in to-clear (initial) 2012-02-10 01:02:42 DEBUG [work.show(66)] # effective block size = 4096 2012-02-10 01:02:42 DEBUG [work.show(82)] # extent physical logical length user_data 2012-02-10 01:02:42 DEBUG [work.show(90)] # 0 905 905 25719 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 1 32770 32770 383 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 2 98306 98306 383 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 3 163842 163842 383 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 4 229378 229378 383 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 5 294906 294906 6 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 6 294914 294914 383 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 7 327663 327663 17 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 8 360183 360183 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 9 360187 360187 5 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 10 360217 360217 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 11 425028 425028 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 12 589700 589700 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 13 589768 589768 56 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 14 618379 618379 5 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 15 618433 618433 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 16 619465 619465 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 17 620400 620400 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 18 620417 620417 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 19 620489 620489 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 20 621505 621505 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 21 622504 622504 6 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 22 622526 622526 66 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 23 678536 678536 126 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 24 678727 678727 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 25 679753 679753 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 26 680129 680129 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 27 680156 680156 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 28 680172 680172 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 29 680186 680186 6 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 30 680657 680657 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 31 681371 681371 5 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 32 681381 681381 3 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 33 681601 681601 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 34 681623 681623 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 35 681736 681736 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 36 681759 681759 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 37 682497 682497 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 38 683529 683529 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 39 684228 684228 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 40 684233 684233 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 41 684254 684254 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 42 684265 684265 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 43 684481 684481 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 44 684919 684919 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 45 685513 685513 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 46 686535 686535 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 47 687561 687561 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 48 687941 687941 3 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 49 697102 697102 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 50 703241 703241 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 51 705295 705295 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 52 705299 705299 5 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 53 709895 709895 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 54 748530 748530 172 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 55 748751 748751 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 56 749711 749711 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 57 749762 749762 6 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 58 750073 750073 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 59 750289 750289 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 60 750621 750621 3 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 61 750625 750625 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 62 750647 750647 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 63 750657 750657 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 64 750677 750677 3 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 65 751241 751241 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 66 751776 751776 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 67 751799 751799 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 68 752265 752265 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 69 752320 752320 6 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 70 752342 752342 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 71 752503 752503 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 72 818951 818951 249 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 73 819202 819202 383 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 74 824196 824196 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 75 826250 826250 6 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 76 831362 831362 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 77 831382 831382 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 78 836493 836493 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 79 836513 836513 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 80 847777 847777 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 81 847797 847797 41 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 82 847887 847887 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 83 848047 848047 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 84 848395 848395 5 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 85 848410 848410 6 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 86 848431 848431 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 87 848463 848463 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 88 848495 848495 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 89 848635 848635 5 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 90 848641 848641 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 91 848657 848657 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 92 848670 848670 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 93 848678 848678 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 94 848694 848694 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 95 848839 848839 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 96 848855 848855 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 97 848900 848900 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 98 849933 849933 3 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 99 881043 881043 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 100 881061 881061 95 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 101 881222 881222 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 102 881697 881697 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 103 881719 881719 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 104 881993 881993 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 105 883009 883009 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 106 883208 883208 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 107 883226 883226 6 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 108 884738 884738 383 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 109 890759 890759 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 110 913048 913048 5 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 111 913069 913069 178 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 112 913548 913548 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 113 914305 914305 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 114 914997 914997 3 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 115 915009 915009 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 116 915027 915027 5 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 117 915042 915042 6 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 118 915273 915273 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 119 916289 916289 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 120 916706 916706 6 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 121 916719 916719 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 122 982601 982601 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 123 982784 982784 38 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 124 982838 982838 202 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 125 1012829 1012829 3 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 126 1013056 1013056 191 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 127 1013263 1013263 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 128 1013313 1013313 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 129 1013697 1013697 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 130 1013716 1013716 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 131 1013732 1013732 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 132 1013746 1013746 6 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 133 1014217 1014217 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 134 1014931 1014931 5 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 135 1014941 1014941 3 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 136 1015113 1015113 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 137 1015183 1015183 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 138 1015296 1015296 5 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 139 1015317 1015317 3 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 140 1046154 1046154 6 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 141 1046288 1046288 31 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 142 1047377 1047377 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 143 1048376 1048376 200 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 144 1089547 1089547 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 145 1089567 1089567 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 146 1100808 1100808 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 147 1100828 1100828 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 148 1114085 1114085 27 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 149 1120775 1120775 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 150 1124814 1124814 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 151 1126861 1126861 3 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 152 1146284 1146284 208 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 153 1146508 1146508 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 154 1223043 1223043 5 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 155 1229964 1229964 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 156 1232018 1232018 6 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 157 1243022 1243022 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 158 1245058 1245058 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 159 1245076 1245076 108 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 160 1277047 1277047 193 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 161 1310350 1310350 141 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 162 1310507 1310507 213 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 163 1362052 1362052 5 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 164 1362073 1362073 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 165 1365154 1365154 190 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 166 1365377 1365377 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 167 1366255 1366255 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 168 1366269 1366269 3 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 169 1366273 1366273 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 170 1366351 1366351 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 171 1367087 1367087 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 172 1367329 1367329 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 173 1367415 1367415 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 174 1367417 1367417 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 175 1368129 1368129 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 176 1369161 1369161 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 177 1369344 1369344 6 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 178 1369366 1369366 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 179 1369929 1369929 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 180 1370945 1370945 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 181 1371160 1371160 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 182 1371177 1371177 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 183 1371311 1371311 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 184 1371982 1371982 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 185 1371986 1371986 6 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 186 1372041 1372041 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 187 1372657 1372657 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 188 1372669 1372669 3 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 189 1372686 1372686 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 190 1372697 1372697 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 191 1372945 1372945 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 192 1373650 1373650 6 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 193 1373671 1373671 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 194 1373961 1373961 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 195 1374025 1374025 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 196 1374039 1374039 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 197 1375049 1375049 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 198 1390154 1390154 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 199 1390174 1390174 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 200 1401416 1401416 5 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 201 1401437 1401437 3 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 202 1403490 1403490 124 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 203 1403663 1403663 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 204 1404607 1404607 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 205 1404687 1404687 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 206 1404700 1404700 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 207 1404716 1404716 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 208 1404732 1404732 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 209 1404751 1404751 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 210 1404923 1404923 5 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 211 1405054 1405054 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 212 1405215 1405215 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 213 1405227 1405227 5 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 214 1405242 1405242 6 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 215 1405249 1405249 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 216 1405263 1405263 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 217 1405270 1405270 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 218 1405278 1405278 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 219 1405295 1405295 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 220 1405406 1405406 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 221 1405423 1405423 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 222 1405439 1405439 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 223 1405471 1405471 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 224 1405697 1405697 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 225 1406729 1406729 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 226 1407745 1407745 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 227 1408744 1408744 280 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 228 1413636 1413636 4 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 229 1415690 1415690 6 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 230 1420804 1420804 5 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 231 1420825 1420825 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 232 1440189 1440189 170 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 233 1474405 1474405 155 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 234 1481222 1481222 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 235 1487307 1487307 5 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 236 1489345 1489345 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 237 1489366 1489366 2 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 238 1500303 1500303 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 239 1504261 1504261 111 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 240 1504388 1504388 193 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 241 1505669 1505669 3 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 242 1506493 1506493 3 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 243 1506497 1506497 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 244 1506515 1506515 5 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 245 1506531 1506531 5 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 246 1506569 1506569 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 247 1539319 1539319 177 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 248 1544875 1544875 30 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 249 1544970 1544970 6 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 250 1545936 1545936 1023 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 251 1548033 1548033 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 252 1549016 1549016 1024 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 253 1550089 1550089 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 254 1551072 1551072 1022 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 255 1552143 1552143 1 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 256 1553153 1553153 7 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 257 1554152 1554152 1023 (0) 2012-02-10 01:02:42 DEBUG [work.show(90)] # 258 1555191 1555191 17657 (0) 2012-02-10 01:02:42 DEBUG [work.show(75)] 2012-02-10 01:02:42 DEBUG [work.show(63)] # 1753 extents in free-space (after to-clear) 2012-02-10 01:02:42 DEBUG [work.show(73)] # no extents in device 2012-02-10 01:02:42 DEBUG [work.show(63)] # 259 extents in loop-holes (initial) 2012-02-10 01:02:42 DEBUG [work.show(73)] # no extents in device (invariant) 2012-02-10 01:02:42 DEBUG [work.show(63)] # 259 extents in loop-holes after device (invariant) 2012-02-10 01:02:42 DEBUG [work.show(73)] # no extents in device (renumbered) 2012-02-10 01:02:42 DEBUG [work.show(63)] # 259 extents in loop-holes (final) 2012-02-10 01:02:42 DEBUG [work.show(73)] # no extents in loop-file (invariant) 2012-02-10 01:02:42 DEBUG [work.show(63)] # 98286 extents in device + loop-file (merged) 2012-02-10 01:02:42 NOTICE [work.analyze(533)] analysis completed: 5.79 gigabytes must be relocated 2012-02-10 01:02:42 DEBUG [work.show(63)] # 74 extents in free-space (invariant) 2012-02-10 01:02:42 DEBUG [work.show(73)] # no extents in primary-storage (= free-space, invariant, contiguous, aligned) 2012-02-10 01:02:42 INFO [work.analyze(602)] primary-storage: located 0.00 bytes (0 fragments) usable in device (free, invariant, contiguous and aligned) 2012-02-10 01:02:42 INFO [work.fill_io_primary_storage(904)] primary-storage: actually using 0.00 bytes (0 fragments) from device 2012-02-10 01:02:42 DEBUG [work.show(73)] # no extents in primary-storage (actually used) 2012-02-10 01:02:42 DEBUG [io/io_posix.create_storage(539)] storage: preemptively reserved contiguous RAM, mmap(length = 778043392, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1) = ok 2012-02-10 01:02:42 NOTICE [io/io_posix.create_storage(564)] allocated 1.00 gigabytes RAM as memory buffer 2012-02-10 01:02:42 INFO [io/io_posix.create_secondary_storage(723)] secondary-storage: writing 742.00 megabytes to '/root/.fstransform/fsremap.job.8/storage.bin' ... 2012-02-10 01:02:43 INFO [io/io_posix.create_secondary_storage(765)] secondary-storage: file created 2012-02-10 01:02:43 NOTICE [io/io_posix.create_storage(603)] secondary-storage is 742.00 megabytes, initialized and mmapped() to contiguous RAM 2012-02-10 01:02:43 INFO [io/io_posix.umount_dev(812)] unmounting device '/dev/loop0'... command: /bin/umount /dev/loop0 2012-02-10 01:02:43 NOTICE [io/io_posix.umount_dev(817)] successfully unmounted device '/dev/loop0' 2012-02-10 01:02:43 NOTICE [work.relocate(936)] everything ready for in-place remapping, this is your LAST chance to quit. 2012-02-10 01:02:43 WARN [work.relocate(937)] press ENTER to proceed, or CTRL+C to quit 2012-02-10 01:02:50 NOTICE [work.relocate(961)] starting in-place remapping. this may take a LONG time ... 2012-02-10 01:02:50 INFO [work.fill_storage(1100)] filling storage by moving 742.00 megabytes from device ... 2012-02-10 01:03:05 INFO [work.fill_storage(1114)] storage filled 2012-02-10 01:03:05 NOTICE [misc.ff_show_progressl(293)] progress: 6.3% done, 5.8 gigabytes still to relocate 2012-02-10 01:03:05 INFO [work.move_to_target(1274)] moving 287.36 megabytes from device to target ... 2012-02-10 01:03:17 INFO [work.move_to_target(1306)] finished moving from device to target 2012-02-10 01:03:17 INFO [work.move_to_target(1274)] moving 557.89 megabytes from storage to target ... 2012-02-10 01:03:25 INFO [work.move_to_target(1306)] finished moving from storage to target 2012-02-10 01:03:25 INFO [work.fill_storage(1100)] filling storage by moving 557.89 megabytes from device ... 2012-02-10 01:03:38 INFO [work.fill_storage(1114)] storage filled 2012-02-10 01:03:38 NOTICE [work.show_progress(1036)] progress: 20.5% done, 5.0 gigabytes still to relocate, estimated 3 minutes left 2012-02-10 01:03:38 INFO [work.move_to_target(1274)] moving 201.44 megabytes from device to target ... 2012-02-10 01:03:47 INFO [work.move_to_target(1306)] finished moving from device to target 2012-02-10 01:03:47 INFO [work.move_to_target(1274)] moving 559.31 megabytes from storage to target ... 2012-02-10 01:03:55 INFO [work.move_to_target(1306)] finished moving from storage to target 2012-02-10 01:03:55 INFO [work.fill_storage(1100)] filling storage by moving 559.31 megabytes from device ... 2012-02-10 01:04:07 INFO [work.fill_storage(1114)] storage filled 2012-02-10 01:04:07 NOTICE [work.show_progress(1036)] progress: 33.3% done, 4.2 gigabytes still to relocate, estimated 3 minutes left 2012-02-10 01:04:07 INFO [work.move_to_target(1274)] moving 198.20 megabytes from device to target ... 2012-02-10 01:04:15 INFO [work.move_to_target(1306)] finished moving from device to target 2012-02-10 01:04:15 INFO [work.move_to_target(1274)] moving 563.92 megabytes from storage to target ... 2012-02-10 01:04:22 INFO [work.move_to_target(1306)] finished moving from storage to target 2012-02-10 01:04:23 INFO [work.fill_storage(1100)] filling storage by moving 563.92 megabytes from device ... 2012-02-10 01:04:32 INFO [work.fill_storage(1114)] storage filled 2012-02-10 01:04:32 NOTICE [work.show_progress(1036)] progress: 46.2% done, 3.5 gigabytes still to relocate, estimated 2 minutes left 2012-02-10 01:04:32 INFO [work.move_to_target(1274)] moving 193.60 megabytes from device to target ... 2012-02-10 01:04:41 INFO [work.move_to_target(1306)] finished moving from device to target 2012-02-10 01:04:41 INFO [work.move_to_target(1274)] moving 566.02 megabytes from storage to target ... 2012-02-10 01:04:50 INFO [work.move_to_target(1306)] finished moving from storage to target 2012-02-10 01:04:50 INFO [work.fill_storage(1100)] filling storage by moving 566.02 megabytes from device ... 2012-02-10 01:05:03 INFO [work.fill_storage(1114)] storage filled 2012-02-10 01:05:03 NOTICE [work.show_progress(1036)] progress: 59.0% done, 2.7 gigabytes still to relocate, estimated 1 minute and 30 seconds left 2012-02-10 01:05:03 INFO [work.move_to_target(1274)] moving 315.80 megabytes from device to target ... 2012-02-10 01:05:17 INFO [work.move_to_target(1306)] finished moving from device to target 2012-02-10 01:05:17 INFO [work.move_to_target(1274)] moving 441.20 megabytes from storage to target ... 2012-02-10 01:05:17 INFO [work.move_to_target(1306)] finished moving from storage to target 2012-02-10 01:05:17 INFO [work.fill_storage(1100)] filling storage by moving 441.20 megabytes from device ... 2012-02-10 01:05:29 INFO [work.fill_storage(1114)] storage filled 2012-02-10 01:05:29 NOTICE [work.show_progress(1036)] progress: 71.8% done, 2.0 gigabytes still to relocate, estimated 1 minute and 3 seconds left 2012-02-10 01:05:29 INFO [work.move_to_target(1274)] moving 304.19 megabytes from device to target ... 2012-02-10 01:05:44 INFO [work.move_to_target(1306)] finished moving from device to target 2012-02-10 01:05:44 INFO [work.move_to_target(1274)] moving 472.15 megabytes from storage to target ... 2012-02-10 01:05:48 INFO [work.move_to_target(1306)] finished moving from storage to target 2012-02-10 01:05:48 INFO [work.fill_storage(1100)] filling storage by moving 472.15 megabytes from device ... 2012-02-10 01:05:58 INFO [work.fill_storage(1114)] storage filled 2012-02-10 01:05:58 NOTICE [work.show_progress(1036)] progress: 84.9% done, 1.2 gigabytes still to relocate, estimated 30 seconds left 2012-02-10 01:05:58 INFO [work.move_to_target(1274)] moving 131.68 megabytes from device to target ... 2012-02-10 01:06:04 INFO [work.move_to_target(1306)] finished moving from device to target 2012-02-10 01:06:04 INFO [work.move_to_target(1274)] moving 619.41 megabytes from storage to target ... 2012-02-10 01:06:14 INFO [work.move_to_target(1306)] finished moving from storage to target 2012-02-10 01:06:14 INFO [work.fill_storage(1100)] filling storage by moving 394.18 megabytes from device ... 2012-02-10 01:06:24 INFO [work.fill_storage(1114)] storage filled 2012-02-10 01:06:24 NOTICE [work.show_progress(1036)] progress: 95.6% done, 516.8 megabytes still to relocate, estimated 10 seconds left 2012-02-10 01:06:24 INFO [work.move_to_target(1274)] moving 516.77 megabytes from storage to target ... 2012-02-10 01:06:33 INFO [work.move_to_target(1306)] finished moving from storage to target 2012-02-10 01:06:33 INFO [work.relocate(1011)] blocks remapping completed. 2012-02-10 01:06:33 INFO [work.clear_free_space(1349)] clearing 215.08 megabytes free-space from device ... 2012-02-10 01:06:39 INFO [work.clear_free_space(1381)] device free-space cleared 2012-02-10 01:06:39 NOTICE [work.run(157)] job completed. fstransform-0.9.4/fsattr/000077500000000000000000000000001345021500300153645ustar00rootroot00000000000000fstransform-0.9.4/fsattr/.cproject000066400000000000000000000304631345021500300172040ustar00rootroot00000000000000 fstransform-0.9.4/fsattr/.project000066400000000000000000000014471345021500300170410ustar00rootroot00000000000000 fsattr org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder full,incremental, org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature fstransform-0.9.4/fsattr/.settings/000077500000000000000000000000001345021500300173025ustar00rootroot00000000000000fstransform-0.9.4/fsattr/.settings/language.settings.xml000066400000000000000000000040361345021500300234510ustar00rootroot00000000000000 fstransform-0.9.4/fsattr/build/000077500000000000000000000000001345021500300164635ustar00rootroot00000000000000fstransform-0.9.4/fsattr/build/Makefile.am000066400000000000000000000003131345021500300205140ustar00rootroot00000000000000AUTOMAKE_OPTIONS = subdir-objects sbin_PROGRAMS = fsattr fsattr_LDADD = @LD_LIBEXT2FS@ @LD_LIBCOM_ERR@ fsattr_SOURCES = \ ../src/e4attr.cc \ ../src/log.cc \ ../src/main.cc \ ../src/mstring.cc fstransform-0.9.4/fsattr/build/Makefile.in000066400000000000000000000460561345021500300205430ustar00rootroot00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : sbin_PROGRAMS = fsattr$(EXEEXT) subdir = fsattr/build ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/tools/ft_cxx_flags.m4 \ $(top_srcdir)/tools/ft_cxx_features.m4 \ $(top_srcdir)/tools/ft_cxx_unordered_map.m4 \ $(top_srcdir)/tools/ft_need_funcs.m4 \ $(top_srcdir)/tools/ft_need_libs.m4 \ $(top_srcdir)/tools/ft_output.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/fsremap/src/config.hh CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" PROGRAMS = $(sbin_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_fsattr_OBJECTS = ../src/e4attr.$(OBJEXT) ../src/log.$(OBJEXT) \ ../src/main.$(OBJEXT) ../src/mstring.$(OBJEXT) fsattr_OBJECTS = $(am_fsattr_OBJECTS) fsattr_DEPENDENCIES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/fsremap/src depcomp = $(SHELL) $(top_srcdir)/tools/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ../src/$(DEPDIR)/e4attr.Po \ ../src/$(DEPDIR)/log.Po ../src/$(DEPDIR)/main.Po \ ../src/$(DEPDIR)/mstring.Po am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(fsattr_SOURCES) DIST_SOURCES = $(fsattr_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/tools/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LD_LIBCOM_ERR = @LD_LIBCOM_ERR@ LD_LIBEXT2FS = @LD_LIBEXT2FS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CXX = @ac_ct_CXX@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = subdir-objects fsattr_LDADD = @LD_LIBEXT2FS@ @LD_LIBCOM_ERR@ fsattr_SOURCES = \ ../src/e4attr.cc \ ../src/log.cc \ ../src/main.cc \ ../src/mstring.cc all: all-am .SUFFIXES: .SUFFIXES: .cc .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu fsattr/build/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu fsattr/build/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) ../src/$(am__dirstamp): @$(MKDIR_P) ../src @: > ../src/$(am__dirstamp) ../src/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) ../src/$(DEPDIR) @: > ../src/$(DEPDIR)/$(am__dirstamp) ../src/e4attr.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/log.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/main.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/mstring.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) fsattr$(EXEEXT): $(fsattr_OBJECTS) $(fsattr_DEPENDENCIES) $(EXTRA_fsattr_DEPENDENCIES) @rm -f fsattr$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(fsattr_OBJECTS) $(fsattr_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f ../src/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/e4attr.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/log.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/mstring.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .cc.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cc.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(sbindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -rm -f ../src/$(DEPDIR)/$(am__dirstamp) -rm -f ../src/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -f ../src/$(DEPDIR)/e4attr.Po -rm -f ../src/$(DEPDIR)/log.Po -rm -f ../src/$(DEPDIR)/main.Po -rm -f ../src/$(DEPDIR)/mstring.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ../src/$(DEPDIR)/e4attr.Po -rm -f ../src/$(DEPDIR)/log.Po -rm -f ../src/$(DEPDIR)/main.Po -rm -f ../src/$(DEPDIR)/mstring.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-sbinPROGRAMS cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-sbinPROGRAMS .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: fstransform-0.9.4/fsattr/src/000077500000000000000000000000001345021500300161535ustar00rootroot00000000000000fstransform-0.9.4/fsattr/src/e4attr.cc000066400000000000000000000255561345021500300177020ustar00rootroot00000000000000/* * fsattr - modify file-system internal data structures * * Copyright (C) 2012 Massimiliano Ghilardi * * 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, version 2 of the License. * * 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 . * * e4attr.cc * * Created on: Apr 14, 2012 * Author: max */ #include "first.hh" #include "types.hh" #if defined(FT_HAVE_ERRNO_H) # include // for errno #elif defined(FT_HAVE_CERRNO) # include // for errno #endif #if defined(FT_HAVE_STDLIB_H) # include // for malloc(), free() #elif defined(FT_HAVE_CSTDLIB) # include // for malloc(), free() #endif #if defined(FT_HAVE_STRING_H) # include // for memcmp(), strncmp() #elif defined(FT_HAVE_CSTRING) # include // for memcmp(), strncmp() #endif #if defined (FT_HAVE_EXT2FS_EXT2FS_H) # include #endif # include "log.hh" FT_NAMESPACE_BEGIN #if defined(FT_HAVE_LIBEXT2FS) && defined(FT_HAVE_LIBCOM_ERR) typedef errcode_t e4_err; typedef ext2_filsys e4_fs; typedef ext2_ino_t e4_inum; typedef ext2_inode e4_inode; typedef ext2_dir_entry e4_dir_iter_; typedef ext2_dir_entry_2 e4_dir_iter; typedef ext2_extent_handle_t e4_extnum; typedef struct ext2fs_extent e4_extent; enum e4attr_extent_op { E4_EXTENT_UNKNOWN_OP, E4_EXTENT_SET_UNINITIALIZED, E4_EXTENT_SET_INITIALIZED }; struct e4attr_ctx { const char * dev_path; e4_fs fs; e4_err err; e4attr_extent_op apply_op; }; #define e4_fail(err, fmt, ...) ff_log(FC_ERROR, 0, fmt ": %s", __VA_ARGS__, error_message(err)) static e4_err e4attr_extents_apply(e4_fs fs, e4_inum inum, e4attr_extent_op apply_op) { e4_extnum extnum; e4_extent extent; e4_err err = ext2fs_extent_open(fs, inum, &extnum); if (err != 0) { e4_fail(err, "ext2fs_extent_open(inode = #%" FT_ULL ") failed", (ft_ull) inum); return err; } int op = EXT2_EXTENT_ROOT; bool init = apply_op == E4_EXTENT_SET_INITIALIZED; const ft_ull max_len = init ? EXT_INIT_MAX_LEN : EXT_UNINIT_MAX_LEN; for (;;) { if ((err = ext2fs_extent_get(extnum, op, &extent)) != 0) { if (err == EXT2_ET_EXTENT_NO_NEXT) err = 0; else e4_fail(err, "ext2fs_extent_get(inode = #%" FT_ULL ", extent = #%" FT_ULL ") failed", (ft_ull) inum, (ft_ull) extnum); break; } op = EXT2_EXTENT_NEXT; if ((extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) || !(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) continue; if (init && !(extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)) continue; if (!init && (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)) continue; if (extent.e_len > max_len) { ff_log(FC_ERROR, 0, "cannot %sinitialize extent %" FT_ULL " - %" FT_ULL " (%" FT_ULL " blocks) in inode #%" FT_ULL ": maximum %sinitialized extent length is %" FT_ULL " blocks", (init ? "" : "un"), (ft_ull) extent.e_lblk, (ft_ull) (extent.e_lblk + (extent.e_len - 1)), (ft_ull) extent.e_len, (ft_ull) inum, (init ? "" : "un"), (ft_ull) max_len); err = -EOVERFLOW; break; } extent.e_flags ^= EXT2_EXTENT_FLAGS_UNINIT; if ((err = ext2fs_extent_replace(extnum, 0, &extent)) != 0) { e4_fail(err, "ext2fs_extent_replace(inode = #%" FT_ULL ", extent = #%" FT_ULL ") failed", (ft_ull) inum, (ft_ull) extnum); break; } } ext2fs_extent_free(extnum); return err; } static int e4attr_dir_iterate(e4_inum dir, int entry, e4_dir_iter_ * iter_, int offset, int blocksize, char * buf, void * priv_data) { e4attr_ctx * ctx = static_cast(priv_data); e4_fs fs = ctx->fs; e4_err & err = ctx->err; e4_dir_iter * iter = reinterpret_cast(iter_); e4_inum inum = iter->inode; int name_len = (int)(unsigned char) iter->name_len; const char * descr; bool is_dir = false, is_file = false; // suppress "unused parameter" warnings (void)entry, (void)offset, (void)blocksize, (void)buf; switch (iter->file_type) { default: case EXT2_FT_UNKNOWN: if ((is_dir = (ext2fs_check_directory(fs, inum) == 0))) descr = "(dir)"; else // avoid trigraph warning descr = "(" "???" ")"; break; case EXT2_FT_REG_FILE: descr = "(file)"; is_file = true; break; case EXT2_FT_DIR: descr = "(dir)"; is_dir = true; break; case EXT2_FT_CHRDEV: descr = "(chr)"; break; case EXT2_FT_BLKDEV: descr = "(blk)"; break; case EXT2_FT_FIFO: descr = "(fifo)"; break; case EXT2_FT_SOCK: descr = "(sock)"; break; case EXT2_FT_SYMLINK: descr = "(slnk)"; break; } ff_log(FC_DEBUG, 0, "%" FT_ULL "\t->%" FT_ULL "\t%s\t%.*s", (ft_ull) dir, (ft_ull) inum, descr, name_len, iter->name); if (is_file) { err = e4attr_extents_apply(fs, inum, ctx->apply_op); // skip "." and ".." } else if (is_dir && inum != dir && (name_len != 2 || memcmp(iter->name, "..", 2))) { char * buf2 = (char *) malloc(fs->blocksize); if (buf2 == 0) { err = ff_log(FC_ERROR, errno, "malloc(%" FT_ULL ") failed", (ft_ull) fs->blocksize); return 1; } if ((err = ext2fs_dir_iterate2(fs, inum, 0, buf2, e4attr_dir_iterate, priv_data)) != 0) e4_fail(err, "ext2fs_dir_iterate2(..., dir_inum = #%" FT_ULL ") failed", (ft_ull) inum); free(buf2); } return err ? 1 : 0; } static e4_err e4attr_run(const char * dev_path, e4attr_extent_op apply_op) { e4attr_ctx ctx; char * buf = NULL; // harcoded? const e4_inum root_inum = 2; bool fs_is_open = false; ctx.dev_path = dev_path; ctx.apply_op = apply_op; e4_fs & fs = ctx.fs; e4_err & err = ctx.err = 0; initialize_ext2_error_table(); do { if ((err = ext2fs_open(dev_path, EXT2_FLAG_RW, 0, 0, unix_io_manager, & fs)) != 0) { e4_fail(err, "ext2fs_open(%s) failed", dev_path); break; } fs_is_open = true; if ((err = ext2fs_check_directory(fs, root_inum)) != 0) { e4_fail(err, "inode #%" FT_ULL " inside device '%s' is not a directory - but it is supposed to be the root directory", dev_path, (ft_ull) root_inum); break; } buf = (char *) malloc(fs->blocksize); if (buf == 0) { err = ff_log(FC_ERROR, errno, "malloc(%" FT_ULL ") failed", (ft_ull) fs->blocksize); break; } if ((err = ext2fs_dir_iterate2(fs, root_inum, 0, buf, e4attr_dir_iterate, static_cast(& ctx))) != 0) e4_fail(err, "ext2fs_dir_iterate2(%s, root_inum = #%" FT_ULL ") failed", dev_path, (ft_ull) root_inum); } while (0); if (buf) free(buf); if (fs_is_open && (err = ext2fs_close(fs)) != 0) e4_fail(err, "ext2fs_close(%s) failed", dev_path); return err; } /** print command-line usage to stdout and return 0 */ static int e4attr_help(const char * program_name) { ff_log(FC_NOTICE, 0, "Usage: %s --files={normal|prealloc} DEVICE", program_name); ff_log(FC_NOTICE, 0, "Modify file-system internal data structures"); return ff_log(FC_NOTICE, 0, "Options:\n" " -- end of options. treat subsequent parameters as arguments\n" " even if they start with '-'\n" " --files=normal set files to normal mode, i.e. show their contents.\n" " --files=prealloc set files to 'preallocated', i.e. clear their contents.\n" " --fstype=FSTYPE specify file system inside device.\n" " --help display this help and exit\n" " --version output version information and exit"); } static int e4attr_version() { return ff_log(FC_NOTICE, 0, "fsattr (fstransform utilities) " FT_VERSION "\n" "Copyright (C) 2012-2017 Massimiliano Ghilardi\n" "\n" "License GPLv2: GNU GPL version 2\n" ".\n" "This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law."); } static int e4attr_usage(const char * program_name) { ff_log(FC_NOTICE, 0, "Try %s --help' for more information.", program_name); return 1; } int e4attr_main(int argc, char ** argv) { const char * program_name = argv[0], * dev_path = NULL; e4attr_extent_op apply_op = E4_EXTENT_UNKNOWN_OP; bool allow_opts = true; while (--argc) { char * arg = * ++argv; if (allow_opts && arg[0] == '-') { if (!strcmp(arg, "--")) allow_opts = false; else if (!strcmp(arg, "--help")) return e4attr_help(program_name); else if (!strcmp(arg, "--version")) return e4attr_version(); else if (!strcmp(arg, "--files=prealloc")) apply_op = E4_EXTENT_SET_UNINITIALIZED; else if (!strcmp(arg, "--files=normal")) apply_op = E4_EXTENT_SET_INITIALIZED; else if (!strncmp(arg, "--fstype=", 9)) { if (strcmp(arg + 9, "ext4")) { ff_log(FC_ERROR, 0, "%s: option '%s' specified, but only supported FSTYPE value is 'ext4'", program_name, arg); return 1; } } else { ff_log(FC_ERROR, 0, "%s: invalid option '%s'", program_name, arg); return e4attr_usage(program_name); } } else dev_path = arg; } if (dev_path == NULL) { ff_log(FC_ERROR, 0, "%s: missing argument DEVICE", program_name); return e4attr_usage(program_name); } if (apply_op == E4_EXTENT_UNKNOWN_OP) { ff_log(FC_ERROR, 0, "%s: missing operation, please specify one of --files=normal or --files=prealloc", program_name); return e4attr_usage(program_name); } e4_err err = ft::e4attr_run(dev_path, apply_op); return err != 0 ? 1 : 0; } #else /* !(defined(FT_HAVE_LIBEXT2FS) && defined(FT_HAVE_LIBCOM_ERR)) */ int e4attr_main(int argc, char ** argv) { const char * program_name = argv[0]; ff_log(FC_ERROR, 0, "%s: this program is a NOT functional because it was compiled without -lext2fs -lcom_err", program_name); return 1; } #endif /* defined(FT_HAVE_LIBEXT2FS) && defined(FT_HAVE_LIBCOM_ERR) */ FT_NAMESPACE_END fstransform-0.9.4/fsattr/src/e4attr.hh000066400000000000000000000017541345021500300177060ustar00rootroot00000000000000/* * fsattr - modify file-system internal data structures * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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, version 2 of the License. * * 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 . * * e4attr.hh * * Created on: Apr 14, 2012 * Author: max */ #ifndef FSATTR_E4ATTR_HH #define FSATTR_E4ATTR_HH #include "types.hh" FT_NAMESPACE_BEGIN int e4attr_main(int argc, char ** argv); FT_NAMESPACE_END #endif /* FSTRANSFORM_LOG_HH */ fstransform-0.9.4/fsattr/src/features.hh000077700000000000000000000000001345021500300253162../../fsremap/src/features.hhustar00rootroot00000000000000fstransform-0.9.4/fsattr/src/first.hh000077700000000000000000000000001345021500300241402../../fsremap/src/first.hhustar00rootroot00000000000000fstransform-0.9.4/fsattr/src/ft_config.hh000077700000000000000000000000001345021500300255562../../fsremap/src/ft_config.hhustar00rootroot00000000000000fstransform-0.9.4/fsattr/src/log.cc000077700000000000000000000000001345021500300232002../../fsremap/src/log.ccustar00rootroot00000000000000fstransform-0.9.4/fsattr/src/log.hh000077700000000000000000000000001345021500300232242../../fsremap/src/log.hhustar00rootroot00000000000000fstransform-0.9.4/fsattr/src/main.cc000066400000000000000000000020421345021500300174040ustar00rootroot00000000000000/* * fsattr - modify file-system internal data structures * * Copyright (C) 2012 Massimiliano Ghilardi * * 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, see . * * main.cc * Created on: Apr 15, 2012 * Author: max */ #include "first.hh" # include "e4attr.hh" // for e4attr_main() # define FA_MAIN(argc, argv) FT_NS e4attr_main(argc, argv) int main(int argc, char ** argv) { return FA_MAIN(argc, argv); } fstransform-0.9.4/fsattr/src/mstring.cc000077700000000000000000000000001345021500300250042../../fsremap/src/mstring.ccustar00rootroot00000000000000fstransform-0.9.4/fsattr/src/mstring.hh000077700000000000000000000000001345021500300250302../../fsremap/src/mstring.hhustar00rootroot00000000000000fstransform-0.9.4/fsattr/src/types.hh000077700000000000000000000000001345021500300241722../../fsremap/src/types.hhustar00rootroot00000000000000fstransform-0.9.4/fsmount_kernel/000077500000000000000000000000001345021500300171145ustar00rootroot00000000000000fstransform-0.9.4/fsmount_kernel/.cproject000066400000000000000000000305331345021500300207320ustar00rootroot00000000000000 fstransform-0.9.4/fsmount_kernel/.project000066400000000000000000000014571345021500300205720ustar00rootroot00000000000000 fsmount_kernel org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder full,incremental, org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature fstransform-0.9.4/fsmount_kernel/.settings/000077500000000000000000000000001345021500300210325ustar00rootroot00000000000000fstransform-0.9.4/fsmount_kernel/.settings/language.settings.xml000066400000000000000000000040401345021500300251740ustar00rootroot00000000000000 fstransform-0.9.4/fsmount_kernel/build/000077500000000000000000000000001345021500300202135ustar00rootroot00000000000000fstransform-0.9.4/fsmount_kernel/build/Makefile.am000066400000000000000000000002271345021500300222500ustar00rootroot00000000000000AUTOMAKE_OPTIONS = subdir-objects sbin_PROGRAMS = fsmount_kernel fsmount_kernel_SOURCES = \ ../src/log.cc \ ../src/main.cc \ ../src/mstring.cc fstransform-0.9.4/fsmount_kernel/build/Makefile.in000066400000000000000000000455151345021500300222720ustar00rootroot00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : sbin_PROGRAMS = fsmount_kernel$(EXEEXT) subdir = fsmount_kernel/build ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/tools/ft_cxx_flags.m4 \ $(top_srcdir)/tools/ft_cxx_features.m4 \ $(top_srcdir)/tools/ft_cxx_unordered_map.m4 \ $(top_srcdir)/tools/ft_need_funcs.m4 \ $(top_srcdir)/tools/ft_need_libs.m4 \ $(top_srcdir)/tools/ft_output.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/fsremap/src/config.hh CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" PROGRAMS = $(sbin_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_fsmount_kernel_OBJECTS = ../src/log.$(OBJEXT) ../src/main.$(OBJEXT) \ ../src/mstring.$(OBJEXT) fsmount_kernel_OBJECTS = $(am_fsmount_kernel_OBJECTS) fsmount_kernel_LDADD = $(LDADD) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/fsremap/src depcomp = $(SHELL) $(top_srcdir)/tools/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ../src/$(DEPDIR)/log.Po ../src/$(DEPDIR)/main.Po \ ../src/$(DEPDIR)/mstring.Po am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(fsmount_kernel_SOURCES) DIST_SOURCES = $(fsmount_kernel_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/tools/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LD_LIBCOM_ERR = @LD_LIBCOM_ERR@ LD_LIBEXT2FS = @LD_LIBEXT2FS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CXX = @ac_ct_CXX@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = subdir-objects fsmount_kernel_SOURCES = \ ../src/log.cc \ ../src/main.cc \ ../src/mstring.cc all: all-am .SUFFIXES: .SUFFIXES: .cc .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu fsmount_kernel/build/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu fsmount_kernel/build/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) ../src/$(am__dirstamp): @$(MKDIR_P) ../src @: > ../src/$(am__dirstamp) ../src/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) ../src/$(DEPDIR) @: > ../src/$(DEPDIR)/$(am__dirstamp) ../src/log.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/main.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/mstring.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) fsmount_kernel$(EXEEXT): $(fsmount_kernel_OBJECTS) $(fsmount_kernel_DEPENDENCIES) $(EXTRA_fsmount_kernel_DEPENDENCIES) @rm -f fsmount_kernel$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(fsmount_kernel_OBJECTS) $(fsmount_kernel_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f ../src/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/log.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/mstring.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .cc.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cc.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(sbindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -rm -f ../src/$(DEPDIR)/$(am__dirstamp) -rm -f ../src/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -f ../src/$(DEPDIR)/log.Po -rm -f ../src/$(DEPDIR)/main.Po -rm -f ../src/$(DEPDIR)/mstring.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ../src/$(DEPDIR)/log.Po -rm -f ../src/$(DEPDIR)/main.Po -rm -f ../src/$(DEPDIR)/mstring.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-sbinPROGRAMS cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-sbinPROGRAMS .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: fstransform-0.9.4/fsmount_kernel/src/000077500000000000000000000000001345021500300177035ustar00rootroot00000000000000fstransform-0.9.4/fsmount_kernel/src/features.hh000077700000000000000000000000001345021500300270462../../fsremap/src/features.hhustar00rootroot00000000000000fstransform-0.9.4/fsmount_kernel/src/first.hh000077700000000000000000000000001345021500300256702../../fsremap/src/first.hhustar00rootroot00000000000000fstransform-0.9.4/fsmount_kernel/src/ft_config.hh000077700000000000000000000000001345021500300273062../../fsremap/src/ft_config.hhustar00rootroot00000000000000fstransform-0.9.4/fsmount_kernel/src/log.cc000077700000000000000000000000001345021500300247302../../fsremap/src/log.ccustar00rootroot00000000000000fstransform-0.9.4/fsmount_kernel/src/log.hh000077700000000000000000000000001345021500300247542../../fsremap/src/log.hhustar00rootroot00000000000000fstransform-0.9.4/fsmount_kernel/src/main.cc000066400000000000000000000220171345021500300211400ustar00rootroot00000000000000/* * fsmount_kernel - invoke raw linux syscall mount(), bypassing /sbin/mount * * Copyright (C) 2017 Massimiliano Ghilardi * * 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, see . * * main.cc * Created on: Jan 15, 2012 * Author: max */ #include "first.hh" #include "log.hh" #include #include #if defined(FT_HAVE_ERRNO_H) # include // for errno #elif defined(FT_HAVE_CERRNO) # include // for errno #endif #if defined(FT_HAVE_STRING_H) # include // for memcmp(), strcmp(), strdup() ... #elif defined(FT_HAVE_CSTRING) # include // for memcmp(), strcmp(), strdup() ... #endif #if defined(FT_HAVE_SYS_MOUNT_H) # include // for mount() #endif #ifndef MS_BIND # define MS_BIND 0 #endif #ifndef MS_DIRSYNC # define MS_DIRSYNC 0 #endif #ifndef MS_LAZYTIME # define MS_LAZYTIME 0 #endif #ifndef MS_REC # define MS_REC 0 #endif #ifndef MS_RELATIME # define MS_RELATIME 0 #endif #ifndef MS_STRICTATIME # define MS_STRICTATIME 0 #endif #ifndef MS_SILENT # define MS_SILENT 0 #endif FT_NAMESPACE_BEGIN static const char * program_name = "fsmount_kernel"; static const char * source = NULL; static const char * target = NULL; static const char * fstype = NULL; static char * options = NULL; static unsigned long mountflags = 0; /** print command-line usage to stdout and return err */ int usage(int err) { ff_log(FC_NOTICE, 0, "Usage: %s [-o OPTIONS] -t FILESYSTEM_TYPE SOURCE TARGET\n", program_name); ff_log(FC_NOTICE, 0, "Call the kernel to mount a filesystem,"); ff_log(FC_NOTICE, 0, "ignoring any userspace helper or wrapper (fuse...)"); ff_log(FC_NOTICE, 0, "Options:\n" " -- end of options. treat subsequent parameters as arguments\n" " even if they start with '-'\n" " -t set the filesystem type. MANDATORY.\n" " -o comma-separated list of mount options.\n" " -h, --help display this help and exit\n" " --version output version information and exit\n"); return err; } /** output version information and return 0 */ int version() { return ff_log(FC_NOTICE, 0, "fsmount_kernel (fstransform utilities) " FT_VERSION "\n" "Copyright (C) 2011-2017 Massimiliano Ghilardi\n" "\n" "License GPLv3+: GNU GPL version 3 or later .\n" "This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law.\n"); } int parse_options() { char * sep, * src = options, * dst = options; unsigned long len; while (src != NULL) { sep = strchr(src, ','); len = sep ? sep - src : strlen(src); if (len == 5 && !memcmp(src, "atime", len)) mountflags &= ~MS_NOATIME; else if (len == 5 && !memcmp(src, "async", len)) mountflags &= ~MS_SYNCHRONOUS; else if (len == 4 && !memcmp(src, "bind", len)) mountflags |= MS_BIND; else if (len == 3 && !memcmp(src, "dev", len)) mountflags &= ~MS_NODEV; else if (len == 8 && !memcmp(src, "diratime", len)) mountflags &= ~MS_NODIRATIME; else if (len == 7 && !memcmp(src, "dirsync", len)) mountflags |= MS_DIRSYNC; else if (len == 4 && !memcmp(src, "exec", len)) mountflags &= ~MS_NOEXEC; else if (len == 8 && !memcmp(src, "lazytime", len)) mountflags |= MS_LAZYTIME; else if (len == 4 && !memcmp(src, "mand", len)) mountflags |= MS_MANDLOCK; else if (len == 6 && !memcmp(src, "nomand", len)) mountflags &= ~MS_MANDLOCK; else if (len == 7 && !memcmp(src, "noatime", len)) mountflags |= MS_NOATIME; else if (len == 5 && !memcmp(src, "nodev", len)) mountflags |= MS_NODEV; else if (len == 10 && !memcmp(src, "nodiratime", len)) mountflags |= MS_NODIRATIME; else if (len == 6 && !memcmp(src, "noexec", len)) mountflags |= MS_NOEXEC; else if (len == 10 && !memcmp(src, "norelatime", len)) mountflags &= ~MS_RELATIME; else if (len == 13 && !memcmp(src, "nostrictatime", len)) mountflags &= ~MS_STRICTATIME; else if (len == 6 && !memcmp(src, "nosuid", len)) mountflags |= MS_NOSUID; else if (len == 5 && !memcmp(src, "rbind", len)) mountflags |= MS_BIND | MS_REC; else if (len == 8 && !memcmp(src, "relatime", len)) mountflags |= MS_RELATIME; else if (len == 7 && !memcmp(src, "remount", len)) mountflags |= MS_REMOUNT; else if (len == 2 && !memcmp(src, "ro", len)) mountflags |= MS_RDONLY; else if (len == 2 && !memcmp(src, "rw", len)) mountflags &= ~MS_RDONLY; else if (len == 5 && !memcmp(src, "slave", len)) mountflags |= MS_SLAVE; else if (len == 6 && !memcmp(src, "shared", len)) mountflags |= MS_SHARED; else if (len == 4 && !memcmp(src, "suid", len)) mountflags &= ~MS_NOSUID; else if (len == 7 && !memcmp(src, "private", len)) mountflags |= MS_PRIVATE; else if (len == 10 && !memcmp(src, "unbindable", len)) mountflags |= MS_UNBINDABLE; else if (len == 6 && !memcmp(src, "silent", len)) mountflags |= MS_SILENT; else if (len == 11 && !memcmp(src, "strictatime", len)) mountflags |= MS_STRICTATIME; else if (len == 4 && !memcmp(src, "sync", len)) mountflags |= MS_SYNCHRONOUS; else { if (dst != options) *dst++ = ','; memmove(dst, src, len); dst += len; } src = sep + (sep != NULL); } if (dst) *dst++ = '\0'; if (!source) { ff_log(FC_ERROR, 0, "%s: missing argument SOURCE", program_name); return usage(1); } if (mountflags & MS_REMOUNT) { return 0; } if (mountflags & MS_BIND) { if (target) return 0; ff_log(FC_ERROR, 0, "%s: missing argument TARGET, required by options 'bind' and 'rbind'", program_name); return usage(1); } if (mountflags & (MS_SHARED|MS_PRIVATE|MS_SLAVE|MS_UNBINDABLE)) { return 0; } if (!target || !fstype) { ff_log(FC_ERROR, 0, "%s: missing %s%s%s", program_name, (target ? "" : "argument TARGET"), (target || fstype ? "" : " and "), (fstype ? "" : "option -t FILESYSTEM_TYPE")); return usage(1); } return 0; } int do_mount() { int err = mount(source, target, fstype, mountflags, options); if (err != 0) err = ff_log(FC_ERROR, errno, "syscall mount(source='%s', target='%s', fstype='%s', mountflags=0x%lx, options='%s') failed", source, (target ? target : ""), (fstype ? fstype : ""), mountflags, (options ? options : "")); return err; } int main(int argc, char ** argv) { const char * arg; bool allow_options = true; if (argc && *argv) program_name = *argv++; while ((arg = *argv++)) { if (allow_options && arg[0] == '-') { if (!strcmp(arg, "--")) allow_options = false; else if (!strcmp(arg, "-h") || !strcmp(arg, "--help")) return usage(0); else if (!strcmp(arg, "--version")) return version(); else if (*argv && !strcmp(arg, "-t")) { fstype = *argv++; } else if (*argv && !strcmp(arg, "-o")) { options = *argv++; } else { ff_log(FC_NOTICE, 0, "%s: invalid option -- '%s'\n", program_name, argv); return usage(1); } } else { if (!source) source = arg; else if (!target) target = arg; else { ff_log(FC_NOTICE, 0, "%s: unexpected argument -- '%s'", program_name, arg); return usage(1); } } } if (options && !(options = strdup(options))) { return ff_log(FC_ERROR, errno, "Out of memory!"); } int err = parse_options(); if (err != 0) return err; return do_mount(); } FT_NAMESPACE_END int main(int argc, char ** argv) { return FT_NS main(argc, argv); } fstransform-0.9.4/fsmount_kernel/src/mstring.cc000077700000000000000000000000001345021500300265342../../fsremap/src/mstring.ccustar00rootroot00000000000000fstransform-0.9.4/fsmount_kernel/src/mstring.hh000077700000000000000000000000001345021500300265602../../fsremap/src/mstring.hhustar00rootroot00000000000000fstransform-0.9.4/fsmount_kernel/src/types.hh000077700000000000000000000000001345021500300257222../../fsremap/src/types.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/000077500000000000000000000000001345021500300153605ustar00rootroot00000000000000fstransform-0.9.4/fsmove/.cproject000066400000000000000000000305251345021500300171770ustar00rootroot00000000000000 fstransform-0.9.4/fsmove/.project000066400000000000000000000014471345021500300170350ustar00rootroot00000000000000 fsmove org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder full,incremental, org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature fstransform-0.9.4/fsmove/.settings/000077500000000000000000000000001345021500300172765ustar00rootroot00000000000000fstransform-0.9.4/fsmove/.settings/language.settings.xml000066400000000000000000000040371345021500300234460ustar00rootroot00000000000000 fstransform-0.9.4/fsmove/build/000077500000000000000000000000001345021500300164575ustar00rootroot00000000000000fstransform-0.9.4/fsmove/build/Makefile.am000066400000000000000000000012521345021500300205130ustar00rootroot00000000000000AUTOMAKE_OPTIONS = subdir-objects sbin_PROGRAMS = fsmove fsmove_SOURCES = \ ../src/args.cc \ ../src/assert.cc \ ../src/copy.cc \ ../src/eta.cc \ ../src/cache/cache_symlink.cc \ ../src/io/disk_stat.cc \ ../src/io/io.cc \ ../src/io/io_posix.cc \ ../src/io/io_posix_dir.cc \ ../src/io/io_prealloc.cc \ ../src/io/util_dir.cc \ ../src/io/util_posix.cc \ ../src/log.cc \ ../src/main.cc \ ../src/misc.cc \ ../src/move.cc \ ../src/mstring.cc \ ../src/rope/rope.cc \ ../src/rope/rope_impl.cc \ ../src/rope/rope_list.cc \ ../src/rope/rope_pool.cc \ ../src/rope/rope_test.cc \ ../src/zstring.cc # ../src/io/util.cc # fsmove_LDADD = $(LD_LIBZ) fstransform-0.9.4/fsmove/build/Makefile.in000066400000000000000000000652421345021500300205350ustar00rootroot00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : sbin_PROGRAMS = fsmove$(EXEEXT) subdir = fsmove/build ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/tools/ft_cxx_flags.m4 \ $(top_srcdir)/tools/ft_cxx_features.m4 \ $(top_srcdir)/tools/ft_cxx_unordered_map.m4 \ $(top_srcdir)/tools/ft_need_funcs.m4 \ $(top_srcdir)/tools/ft_need_libs.m4 \ $(top_srcdir)/tools/ft_output.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/fsremap/src/config.hh CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" PROGRAMS = $(sbin_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_fsmove_OBJECTS = ../src/args.$(OBJEXT) ../src/assert.$(OBJEXT) \ ../src/copy.$(OBJEXT) ../src/eta.$(OBJEXT) \ ../src/cache/cache_symlink.$(OBJEXT) \ ../src/io/disk_stat.$(OBJEXT) ../src/io/io.$(OBJEXT) \ ../src/io/io_posix.$(OBJEXT) ../src/io/io_posix_dir.$(OBJEXT) \ ../src/io/io_prealloc.$(OBJEXT) ../src/io/util_dir.$(OBJEXT) \ ../src/io/util_posix.$(OBJEXT) ../src/log.$(OBJEXT) \ ../src/main.$(OBJEXT) ../src/misc.$(OBJEXT) \ ../src/move.$(OBJEXT) ../src/mstring.$(OBJEXT) \ ../src/rope/rope.$(OBJEXT) ../src/rope/rope_impl.$(OBJEXT) \ ../src/rope/rope_list.$(OBJEXT) \ ../src/rope/rope_pool.$(OBJEXT) \ ../src/rope/rope_test.$(OBJEXT) ../src/zstring.$(OBJEXT) fsmove_OBJECTS = $(am_fsmove_OBJECTS) fsmove_LDADD = $(LDADD) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/fsremap/src depcomp = $(SHELL) $(top_srcdir)/tools/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ../src/$(DEPDIR)/args.Po \ ../src/$(DEPDIR)/assert.Po ../src/$(DEPDIR)/copy.Po \ ../src/$(DEPDIR)/eta.Po ../src/$(DEPDIR)/log.Po \ ../src/$(DEPDIR)/main.Po ../src/$(DEPDIR)/misc.Po \ ../src/$(DEPDIR)/move.Po ../src/$(DEPDIR)/mstring.Po \ ../src/$(DEPDIR)/zstring.Po \ ../src/cache/$(DEPDIR)/cache_symlink.Po \ ../src/io/$(DEPDIR)/disk_stat.Po ../src/io/$(DEPDIR)/io.Po \ ../src/io/$(DEPDIR)/io_posix.Po \ ../src/io/$(DEPDIR)/io_posix_dir.Po \ ../src/io/$(DEPDIR)/io_prealloc.Po \ ../src/io/$(DEPDIR)/util_dir.Po \ ../src/io/$(DEPDIR)/util_posix.Po \ ../src/rope/$(DEPDIR)/rope.Po \ ../src/rope/$(DEPDIR)/rope_impl.Po \ ../src/rope/$(DEPDIR)/rope_list.Po \ ../src/rope/$(DEPDIR)/rope_pool.Po \ ../src/rope/$(DEPDIR)/rope_test.Po am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(fsmove_SOURCES) DIST_SOURCES = $(fsmove_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/tools/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LD_LIBCOM_ERR = @LD_LIBCOM_ERR@ LD_LIBEXT2FS = @LD_LIBEXT2FS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CXX = @ac_ct_CXX@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = subdir-objects fsmove_SOURCES = \ ../src/args.cc \ ../src/assert.cc \ ../src/copy.cc \ ../src/eta.cc \ ../src/cache/cache_symlink.cc \ ../src/io/disk_stat.cc \ ../src/io/io.cc \ ../src/io/io_posix.cc \ ../src/io/io_posix_dir.cc \ ../src/io/io_prealloc.cc \ ../src/io/util_dir.cc \ ../src/io/util_posix.cc \ ../src/log.cc \ ../src/main.cc \ ../src/misc.cc \ ../src/move.cc \ ../src/mstring.cc \ ../src/rope/rope.cc \ ../src/rope/rope_impl.cc \ ../src/rope/rope_list.cc \ ../src/rope/rope_pool.cc \ ../src/rope/rope_test.cc \ ../src/zstring.cc all: all-am .SUFFIXES: .SUFFIXES: .cc .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu fsmove/build/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu fsmove/build/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) ../src/$(am__dirstamp): @$(MKDIR_P) ../src @: > ../src/$(am__dirstamp) ../src/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) ../src/$(DEPDIR) @: > ../src/$(DEPDIR)/$(am__dirstamp) ../src/args.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/assert.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/copy.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/eta.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/cache/$(am__dirstamp): @$(MKDIR_P) ../src/cache @: > ../src/cache/$(am__dirstamp) ../src/cache/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) ../src/cache/$(DEPDIR) @: > ../src/cache/$(DEPDIR)/$(am__dirstamp) ../src/cache/cache_symlink.$(OBJEXT): ../src/cache/$(am__dirstamp) \ ../src/cache/$(DEPDIR)/$(am__dirstamp) ../src/io/$(am__dirstamp): @$(MKDIR_P) ../src/io @: > ../src/io/$(am__dirstamp) ../src/io/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) ../src/io/$(DEPDIR) @: > ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/io/disk_stat.$(OBJEXT): ../src/io/$(am__dirstamp) \ ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/io/io.$(OBJEXT): ../src/io/$(am__dirstamp) \ ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/io/io_posix.$(OBJEXT): ../src/io/$(am__dirstamp) \ ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/io/io_posix_dir.$(OBJEXT): ../src/io/$(am__dirstamp) \ ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/io/io_prealloc.$(OBJEXT): ../src/io/$(am__dirstamp) \ ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/io/util_dir.$(OBJEXT): ../src/io/$(am__dirstamp) \ ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/io/util_posix.$(OBJEXT): ../src/io/$(am__dirstamp) \ ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/log.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/main.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/misc.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/move.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/mstring.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/rope/$(am__dirstamp): @$(MKDIR_P) ../src/rope @: > ../src/rope/$(am__dirstamp) ../src/rope/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) ../src/rope/$(DEPDIR) @: > ../src/rope/$(DEPDIR)/$(am__dirstamp) ../src/rope/rope.$(OBJEXT): ../src/rope/$(am__dirstamp) \ ../src/rope/$(DEPDIR)/$(am__dirstamp) ../src/rope/rope_impl.$(OBJEXT): ../src/rope/$(am__dirstamp) \ ../src/rope/$(DEPDIR)/$(am__dirstamp) ../src/rope/rope_list.$(OBJEXT): ../src/rope/$(am__dirstamp) \ ../src/rope/$(DEPDIR)/$(am__dirstamp) ../src/rope/rope_pool.$(OBJEXT): ../src/rope/$(am__dirstamp) \ ../src/rope/$(DEPDIR)/$(am__dirstamp) ../src/rope/rope_test.$(OBJEXT): ../src/rope/$(am__dirstamp) \ ../src/rope/$(DEPDIR)/$(am__dirstamp) ../src/zstring.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) fsmove$(EXEEXT): $(fsmove_OBJECTS) $(fsmove_DEPENDENCIES) $(EXTRA_fsmove_DEPENDENCIES) @rm -f fsmove$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(fsmove_OBJECTS) $(fsmove_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f ../src/*.$(OBJEXT) -rm -f ../src/cache/*.$(OBJEXT) -rm -f ../src/io/*.$(OBJEXT) -rm -f ../src/rope/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/args.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/assert.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/copy.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/eta.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/log.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/misc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/move.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/mstring.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/zstring.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/cache/$(DEPDIR)/cache_symlink.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/io/$(DEPDIR)/disk_stat.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/io/$(DEPDIR)/io.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/io/$(DEPDIR)/io_posix.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/io/$(DEPDIR)/io_posix_dir.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/io/$(DEPDIR)/io_prealloc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/io/$(DEPDIR)/util_dir.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/io/$(DEPDIR)/util_posix.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/rope/$(DEPDIR)/rope.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/rope/$(DEPDIR)/rope_impl.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/rope/$(DEPDIR)/rope_list.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/rope/$(DEPDIR)/rope_pool.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/rope/$(DEPDIR)/rope_test.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .cc.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cc.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(sbindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -rm -f ../src/$(DEPDIR)/$(am__dirstamp) -rm -f ../src/$(am__dirstamp) -rm -f ../src/cache/$(DEPDIR)/$(am__dirstamp) -rm -f ../src/cache/$(am__dirstamp) -rm -f ../src/io/$(DEPDIR)/$(am__dirstamp) -rm -f ../src/io/$(am__dirstamp) -rm -f ../src/rope/$(DEPDIR)/$(am__dirstamp) -rm -f ../src/rope/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -f ../src/$(DEPDIR)/args.Po -rm -f ../src/$(DEPDIR)/assert.Po -rm -f ../src/$(DEPDIR)/copy.Po -rm -f ../src/$(DEPDIR)/eta.Po -rm -f ../src/$(DEPDIR)/log.Po -rm -f ../src/$(DEPDIR)/main.Po -rm -f ../src/$(DEPDIR)/misc.Po -rm -f ../src/$(DEPDIR)/move.Po -rm -f ../src/$(DEPDIR)/mstring.Po -rm -f ../src/$(DEPDIR)/zstring.Po -rm -f ../src/cache/$(DEPDIR)/cache_symlink.Po -rm -f ../src/io/$(DEPDIR)/disk_stat.Po -rm -f ../src/io/$(DEPDIR)/io.Po -rm -f ../src/io/$(DEPDIR)/io_posix.Po -rm -f ../src/io/$(DEPDIR)/io_posix_dir.Po -rm -f ../src/io/$(DEPDIR)/io_prealloc.Po -rm -f ../src/io/$(DEPDIR)/util_dir.Po -rm -f ../src/io/$(DEPDIR)/util_posix.Po -rm -f ../src/rope/$(DEPDIR)/rope.Po -rm -f ../src/rope/$(DEPDIR)/rope_impl.Po -rm -f ../src/rope/$(DEPDIR)/rope_list.Po -rm -f ../src/rope/$(DEPDIR)/rope_pool.Po -rm -f ../src/rope/$(DEPDIR)/rope_test.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ../src/$(DEPDIR)/args.Po -rm -f ../src/$(DEPDIR)/assert.Po -rm -f ../src/$(DEPDIR)/copy.Po -rm -f ../src/$(DEPDIR)/eta.Po -rm -f ../src/$(DEPDIR)/log.Po -rm -f ../src/$(DEPDIR)/main.Po -rm -f ../src/$(DEPDIR)/misc.Po -rm -f ../src/$(DEPDIR)/move.Po -rm -f ../src/$(DEPDIR)/mstring.Po -rm -f ../src/$(DEPDIR)/zstring.Po -rm -f ../src/cache/$(DEPDIR)/cache_symlink.Po -rm -f ../src/io/$(DEPDIR)/disk_stat.Po -rm -f ../src/io/$(DEPDIR)/io.Po -rm -f ../src/io/$(DEPDIR)/io_posix.Po -rm -f ../src/io/$(DEPDIR)/io_posix_dir.Po -rm -f ../src/io/$(DEPDIR)/io_prealloc.Po -rm -f ../src/io/$(DEPDIR)/util_dir.Po -rm -f ../src/io/$(DEPDIR)/util_posix.Po -rm -f ../src/rope/$(DEPDIR)/rope.Po -rm -f ../src/rope/$(DEPDIR)/rope_impl.Po -rm -f ../src/rope/$(DEPDIR)/rope_list.Po -rm -f ../src/rope/$(DEPDIR)/rope_pool.Po -rm -f ../src/rope/$(DEPDIR)/rope_test.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-sbinPROGRAMS cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-sbinPROGRAMS .PRECIOUS: Makefile # ../src/io/util.cc # fsmove_LDADD = $(LD_LIBZ) # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: fstransform-0.9.4/fsmove/src/000077500000000000000000000000001345021500300161475ustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/args.cc000066400000000000000000000024161345021500300174150ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * args.cc * * Created on: Mar 21, 2011 * Author: max */ #include "first.hh" #include "args.hh" // for fm_args FT_NAMESPACE_BEGIN /** default constructor */ fm_args::fm_args() : program_name("fsmove"), io_args(), exclude_list(NULL), inode_cache_path(NULL), io_kind(FC_IO_AUTODETECT), ui_kind(FC_UI_NONE), force_run(false), simulate_run(false) { } FT_NAMESPACE_END fstransform-0.9.4/fsmove/src/args.hh000066400000000000000000000036101345021500300174240ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * main.hh * * Created on: Mar 20, 2011 * Author: max */ #ifndef FSMOVE_ARGS_HH #define FSMOVE_ARGS_HH #include "types.hh" // for ft_uint, ft_size #include "io/io.hh" // for FC_ARGS_COUNT FT_NAMESPACE_BEGIN enum fm_io_kind { FC_IO_AUTODETECT, FC_IO_POSIX, FC_IO_PREALLOC }; enum fm_ui_kind { FC_UI_NONE }; class fm_args { public: const char * program_name; // detected from command line. default: "fsmove" const char * io_args[FT_IO_NS fm_io::FC_ARGS_COUNT]; char const * const * exclude_list; // NULL-terminated array of files _not_ to move const char * inode_cache_path; fm_io_kind io_kind; // if FC_IO_AUTODETECT, will autodetect fm_ui_kind ui_kind; // default is FC_UI_NONE bool force_run; // if true, some sanity checks will be WARNINGS instead of ERRORS bool simulate_run; // if true, move algorithm runs WITHOUT actually moving/preallocating any file/directory/special-device fm_args(); }; FT_NAMESPACE_END #endif /* FSMOVE_ARGS_HH */ fstransform-0.9.4/fsmove/src/assert.cc000077700000000000000000000000001345021500300244342../../fsremap/src/assert.ccustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/assert.hh000077700000000000000000000000001345021500300244602../../fsremap/src/assert.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/autoconf.hh000077700000000000000000000000001345021500300253122../../fsremap/src/autoconf.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/cache/000077500000000000000000000000001345021500300172125ustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/cache/cache.hh000077700000000000000000000000001345021500300263052../../../fsremap/src/cache/cache.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/cache/cache_adaptor.hh000077700000000000000000000000001345021500300315312../../../fsremap/src/cache/cache_adaptor.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/cache/cache_mem.hh000077700000000000000000000000001345021500300300012../../../fsremap/src/cache/cache_mem.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/cache/cache_symlink.cc000077700000000000000000000000001345021500300315752../../../fsremap/src/cache/cache_symlink.ccustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/cache/cache_symlink.hh000077700000000000000000000000001345021500300316212../../../fsremap/src/cache/cache_symlink.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/check.hh000077700000000000000000000000001345021500300240102../../fsremap/src/check.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/copy.cc000077700000000000000000000000001345021500300235562../../fsremap/src/copy.ccustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/copy.hh000077700000000000000000000000001345021500300236022../../fsremap/src/copy.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/eta.cc000077700000000000000000000000001345021500300231542../../fsremap/src/eta.ccustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/eta.hh000077700000000000000000000000001345021500300232002../../fsremap/src/eta.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/features.hh000077700000000000000000000000001345021500300253122../../fsremap/src/features.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/first.hh000077700000000000000000000000001345021500300241342../../fsremap/src/first.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/ft_config.hh000077700000000000000000000000001345021500300255522../../fsremap/src/ft_config.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/fwd.hh000066400000000000000000000022551345021500300172540ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * fwd.hh * * Created on: Sep 21, 2011 * Author: max */ #ifndef FSMOVE_FWD_HH #define FSMOVE_FWD_HH #include "check.hh" FT_NAMESPACE_BEGIN class fm_args; class fm_move; FT_NAMESPACE_END FT_IO_NAMESPACE_BEGIN class fm_io; class fm_io_posix; FT_IO_NAMESPACE_END #endif /* FSMOVE_FWD_HH */ fstransform-0.9.4/fsmove/src/io/000077500000000000000000000000001345021500300165565ustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/io/disk_stat.cc000066400000000000000000000047231345021500300210600ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/disk_stat.cc * * Created on: Oct 05, 2011 * Author: max */ #include "../first.hh" #include "../log.hh" // for ff_log() #include "../misc.hh" // for ff_pretty_size() #include "disk_stat.hh" // for fm_disk_stat FT_IO_NAMESPACE_BEGIN /** constructor */ fm_disk_stat::fm_disk_stat() : this_name(), this_total(0), this_free(0) { } /** clear all data stored in this object */ void fm_disk_stat::clear() { this_name.clear(); this_total = this_free = 0; } /** * set the free disk space. * returns 0, or error if free disk space becomes critically low */ int fm_disk_stat::set_free(ft_uoff free) { this_free = free; int err = 0; if (is_too_low_free_space(free)) { double pretty_size = 0.0; const char * pretty_label = ff_pretty_size(free, & pretty_size); ff_log(FC_ERROR, 0, "free space on %s device is critically low: only %.2f %sbytes left, ABORTING!!!", this_name.c_str(), pretty_size, pretty_label); err = -ENOSPC; } return err; } /** * return true if 'free' amount of free space would trigger a 'critically low free space' error */ bool fm_disk_stat::is_too_low_free_space(ft_uoff free) const { /** * if file system is smaller than 6GB, critically low free space is 96kbytes. * if file system is between 6GB and 64TB, critically low free space is total disk space divided 65536 (i.e. 0.0015%). * if file system is larger than 64TB, critically low free space is 1Gbyte. */ return free <= THRESHOLD_MIN || (free <= THRESHOLD_MAX && free <= (this_total >> 16)); } FT_IO_NAMESPACE_END fstransform-0.9.4/fsmove/src/io/disk_stat.hh000066400000000000000000000063741345021500300210760ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/disk_stat.hh * * Created on: Oct 05, 2011 * Author: max */ #ifndef FSMOVE_IO_DISK_STAT_HH #define FSMOVE_IO_DISK_STAT_HH #include "../check.hh" #include "../types.hh" // for ft_uoff, ft_string FT_IO_NAMESPACE_BEGIN /** * class to keep track of disk total and free space */ class fm_disk_stat { private: enum { _96kbytes = (ft_uoff)96 << 10, _1Gbyte = (ft_uoff)1 << 30 }; ft_string this_name; ft_uoff this_total, this_free; public: /** * if file systems is smaller than 6GB, critically low free space is 96kbytes. * if file systems is between 6GB and 64TB, critically low free space is total disk space divided 65536 (i.e. 0.0015%). * if file systems is larger than 64TB, critically low free space is 1Gbyte. */ enum { // THRESHOLD_MIN must be somewhat larger than fm_io_posix::FT_BUFSIZE (currently 64k) THRESHOLD_MIN = _96kbytes, THRESHOLD_MAX = _1Gbyte, }; /** constructor */ fm_disk_stat(); /** compiler-generated copy constructor is fine */ // const fm_disk_stat & fm_disk_stat(const fm_disk_stat &); /** compiler-generated destructor is fine */ // ~fm_disk_stat(); /** compiler-generated assignment operator is fine */ // const fm_disk_stat & operator=(const fm_disk_stat &); /** clear all data stored in this object */ void clear(); /** get the disk name */ FT_INLINE const ft_string & get_name() const { return this_name; } /** set the disk name */ FT_INLINE void set_name(const ft_string & name) { this_name = name; } /** return the total disk space */ FT_INLINE ft_uoff get_total() const { return this_total; } /** set the total disk space */ FT_INLINE void set_total(ft_uoff total) { this_total = total; } /** return the free disk space */ FT_INLINE ft_uoff get_free() const { return this_free; } /** * set the free disk space. * returns 0, or error if free disk space becomes critically low */ int set_free(ft_uoff free); /** * return true if 'free' amount of free space would trigger a 'critically low free space' error */ bool is_too_low_free_space(ft_uoff free) const; /** return the used disk space */ FT_INLINE ft_uoff get_used() const { return this_free < this_total ? this_total - this_free : 0; } }; FT_IO_NAMESPACE_END #endif /* FSMOVE_IO_IO_HH */ fstransform-0.9.4/fsmove/src/io/io.cc000066400000000000000000000217701345021500300175030ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/io.cc * * Created on: Sep 20, 2011 * Author: max */ #include "../first.hh" #include "../args.hh" // for fm_args #include "../assert.hh" // for ff_assert() #include "../misc.hh" // for ff_show_progress(), ff_now() #include "io.hh" // for fm_io #include "cache/cache_mem.hh" // for ft_cache_mem #include "cache/cache_symlink.hh" // for ft_cache_symlink_kv #if defined(FT_HAVE_MATH_H) # include // for sqrt() #elif defined(FT_HAVE_CMATH) # include // for sqrt() #endif #if defined(FT_HAVE_STRING_H) # include // for strcmp() #elif defined(FT_HAVE_CSTRING) # include // for strcmp() #endif FT_IO_NAMESPACE_BEGIN char const * const fm_io::label[] = { "source", "target" }; char const * const fm_io::LABEL[] = { "SOURCE", "TARGET" }; /** constructor */ fm_io::fm_io() : this_inode_cache(NULL), this_exclude_set(), this_source_stat(), this_target_stat(), this_source_root(), this_target_root(), this_eta(), this_work_total(0), this_work_report_threshold(0), this_work_done(0), this_work_last_reported(0), this_work_last_reported_time(0.0), this_progress_msg(NULL), this_force_run(false), this_simulate_run(false) { } /** * destructor. * sub-classes must override it to call close() */ fm_io::~fm_io() { // in case it's != NULL delete this_inode_cache; } /** * open this fm_io. * sub-classes must override this method to perform appropriate initialization */ int fm_io::open(const fm_args & args) { const char * arg1 = args.io_args[FC_SOURCE_ROOT], * arg2 = args.io_args[FC_TARGET_ROOT]; int err = 0; do { if (arg1 == NULL) { ff_log(FC_ERROR, 0, "missing arguments: %s %s", label[FC_SOURCE_ROOT], label[FC_TARGET_ROOT]); err = -EINVAL; break; } if (arg2 == NULL) { ff_log(FC_ERROR, 0, "missing argument: %s", label[FC_TARGET_ROOT]); err = -EINVAL; break; } const char * inode_cache_path = args.inode_cache_path; delete this_inode_cache; this_inode_cache = NULL; if (inode_cache_path != NULL) { ft_cache_symlink_kv * icp = new ft_cache_symlink_kv(inode_cache_path); err = icp->init(inode_cache_path); if (err != 0) { delete icp; break; } // icp->get_path() removes trailing '/' unless it's exactly the path "/" inode_cache_path = icp->get_path(); this_inode_cache = icp; } else this_inode_cache = new ft_cache_mem(); this_source_stat.set_name("source"); this_target_stat.set_name("target"); this_source_root = arg1; this_target_root = arg2; this_eta.clear(); this_work_total = this_work_report_threshold = this_work_done = this_work_last_reported = 0; this_force_run = args.force_run; this_simulate_run = args.simulate_run; this_progress_msg = " still to move"; char const * const * exclude_list = args.exclude_list; if (exclude_list != NULL) { for (; * exclude_list != NULL; ++exclude_list) this_exclude_set.insert(* exclude_list); } // do NOT move the inode-cache! if (inode_cache_path != NULL) { this_exclude_set.insert(inode_cache_path); } } while (0); return err; } int fm_io::inode_cache_find_or_add(ft_inode inode, ft_string & path) { ft_size root_len = this_target_root.length(); ff_assert(path.length() >= root_len && path.compare(0, root_len, this_target_root) == 0); ft_string short_path = path.substr(root_len); int err = this_inode_cache->find_or_add(inode, short_path); if (err == 1) path = this_target_root + short_path; return err; } int fm_io::inode_cache_find_and_delete(ft_inode inode, ft_string & path) { ft_size root_len = this_target_root.length(); ff_assert(path.length() >= root_len && path.compare(0, root_len, this_target_root) == 0); ft_string short_path = path.substr(root_len); int err = this_inode_cache->find_and_delete(inode, short_path); if (err == 1) path = this_target_root + short_path; return err; } /** * returns error if source or target file-system are almost full (typical threshold is 97%) */ int fm_io::is_almost_full(const fm_disk_stat & stat) const { ft_uoff total = stat.get_total(); int err = 0; if (total != 0) { ft_uoff used = stat.get_used(); double percentage = 100.0 * ((double) used / total); if (percentage > 97.0) { bool can_force = percentage <= 99.0; bool is_warn = this_force_run && can_force; ff_log(is_warn ? FC_WARN : FC_ERROR, 0, "%s file-system is %4.1f%% full%s%s", stat.get_name().c_str(), percentage, (is_warn ? ", continuing anyway due to -f" : ", cowardly refusing to run"), (!is_warn && can_force ? ". use option '-f' to override this safety check AT YOUR OWN RISK" : "")); err = is_warn ? 0 : -ENOSPC; } } return err; } /** * set total number of bytes to move (may include estimated overhead for special files, inodes...), * reset total number of bytes moved, * initialize this_eta to 0% at current time * * returns error if source or target file-system are almost full (typical threshold is 97%) */ int fm_io::init_work() { int err = is_almost_full(source_stat()); if (err == 0) err = is_almost_full(target_stat()); if (err != 0) return err; ft_uoff source_used = source_stat().get_used(); ft_uoff target_used = target_stat().get_used(); ft_uoff work_total = source_used > target_used ? source_used - target_used : 0; this_work_total = work_total; ft_uoff work_total_GB = work_total >> 30; if (work_total_GB <= 4) /* up to 4GB, report approximately every 5% progress */ this_work_report_threshold = work_total / 20; else if (work_total_GB <= 100) /* up to 100GB, report approximately every 2% progress */ this_work_report_threshold = work_total / 50; else /* above 100GB, report approximately every 2GB * sqrt(size/100GB) */ this_work_report_threshold = (ft_uoff) (((ft_uoff)2 << 30) * sqrt(0.01 * work_total_GB)); this_work_done = this_work_last_reported = 0; ff_now(this_work_last_reported_time); this_eta.add(0.0); return err; } /** * add to number of bytes moved until now (may include estimated overhead for special files, inodes...) * also periodically invokes show_progress() */ void fm_io::add_work_done(ft_uoff work_done) { this_work_done += work_done; if (this_work_total == 0 || this_work_report_threshold == 0 || this_work_done - this_work_last_reported < this_work_report_threshold) return; this_work_last_reported = this_work_done; ff_now(this_work_last_reported_time); show_progress(FC_INFO); } /** show human-readable progress indication, bytes still to move, and estimated time left */ void fm_io::show_progress(ft_log_level log_level) { ft_uoff moved_len = this_work_done, work_total = this_work_total; if (work_total == 0) return; if (moved_len > work_total) moved_len = work_total; double percentage = 0.0, time_left = -1.0; percentage = moved_len / (double)work_total; time_left = this_eta.add(percentage); percentage *= 100.0; const char * simul_msg = ""; if (simulate_run()) { simul_msg = "(simulated) "; time_left = -1.0; } ff_show_progress(log_level, simul_msg, percentage, work_total - moved_len, this_progress_msg, time_left); } /** * close this fm_io. * sub-classes must override this method to perform appropriate cleanup */ void fm_io::close() { this_exclude_set.clear(); this_source_stat.clear(); this_target_stat.clear(); this_source_root.clear(); this_target_root.clear(); this_eta.clear(); this_work_done = this_work_last_reported = this_work_total = 0; this_progress_msg = NULL; this_force_run = this_simulate_run = false; delete this_inode_cache; this_inode_cache = NULL; } FT_IO_NAMESPACE_END fstransform-0.9.4/fsmove/src/io/io.hh000066400000000000000000000116301345021500300175070ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/io.hh * * Created on: Sep 20, 2011 * Author: max */ #ifndef FSMOVE_IO_IO_HH #define FSMOVE_IO_IO_HH #include "../check.hh" #include "../types.hh" // for ft_string, ft_uoff #include "../eta.hh" // for ft_eta #include "../log.hh" // for ft_log_level, also for ff_log() used by io.cc #include "../fwd.hh" // for fm_args #include "../cache/cache.hh" // for ft_cache #include "disk_stat.hh" // for fm_disk_stat #include // for std::set FT_IO_NAMESPACE_BEGIN /** * abstract base class for all I/O implementations * that actually move files around */ class fm_io { private: ft_cache * this_inode_cache; std::set this_exclude_set; fm_disk_stat this_source_stat, this_target_stat; ft_string this_source_root, this_target_root; ft_eta this_eta; ft_uoff this_work_total, this_work_report_threshold; ft_uoff this_work_done, this_work_last_reported; double this_work_last_reported_time; const char * this_progress_msg; bool this_force_run, this_simulate_run; /** * returns error if source or target file-system are almost full (typical threshold is 97%) */ int is_almost_full(const fm_disk_stat & stat) const; protected: int inode_cache_find_or_add(ft_inode inode, ft_string & path); int inode_cache_find_and_delete(ft_inode inode, ft_string & path); FT_INLINE fm_disk_stat & source_stat() { return this_source_stat; } FT_INLINE fm_disk_stat & target_stat() { return this_target_stat; } FT_INLINE void progress_msg(const char * msg) { this_progress_msg = msg; } /** * use source_stat and target_stat to compute total number of bytes to move * (may include estimated overhead for special files, inodes...), * reset total number of bytes moved, * initialize this_eta to 0% at current time * * returns error if source or target file-system are almost full (typical threshold is 97%) */ int init_work(); /** * add to number of bytes moved until now (may include estimated overhead for special files, inodes...) * also periodically invokes show_progress() */ void add_work_done(ft_uoff work_done); /** show human-readable progress indication, bytes still to move, and estimated time left */ void show_progress(ft_log_level log_level = FC_NOTICE); public: enum { FC_SOURCE_ROOT = 0, FC_TARGET_ROOT, FC_ARGS_COUNT = 2, // must be equal to count of preceding enum constants }; static char const * const label[]; // source, target static char const * const LABEL[]; // SOURCE, TARGET /** constructor */ fm_io(); /** * destructor. * sub-classes must override it to call close() */ virtual ~fm_io(); /** return true if this ft_io is currently (and correctly) open */ virtual bool is_open() const = 0; /** * open this fm_io. * sub-classes must override this method to perform appropriate initialization */ virtual int open(const fm_args & args); /** core of recursive move algorithm, actually moves the whole source tree into target */ virtual int move() = 0; /** * close this fm_io. * sub-classes must override this method to perform appropriate cleanup */ virtual void close(); /** * return the set of source files NOT to move */ FT_INLINE const std::set & exclude_set() const { return this_exclude_set; } /** * return the top-most source path to move from */ FT_INLINE const ft_string & source_root() const { return this_source_root; } /** * return the top-most target path to move to */ FT_INLINE const ft_string & target_root() const { return this_target_root; } /** * return the force_run flag */ FT_INLINE bool force_run() const { return this_force_run; } /** * return the simulate_run flag */ FT_INLINE bool simulate_run() const { return this_simulate_run; } }; FT_IO_NAMESPACE_END #endif /* FSMOVE_IO_IO_HH */ fstransform-0.9.4/fsmove/src/io/io_posix.cc000066400000000000000000001043321345021500300207210ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/io_posix.cc * * Created on: Sep 22, 2011 * Author: max */ #include "../first.hh" #if defined(FT_HAVE_CERRNO) # include // for errno and error codes #elif defined(FT_HAVE_ERRNO_H) # include #endif #if defined(FT_HAVE_CLIMITS) # include // for PATH_MAX #elif defined(FT_HAVE_LIMITS_H) # include // for PATH_MAX #endif #if defined(FT_HAVE_CSTDIO) # include // for rename() #elif defined(FT_HAVE_STDIO_H) # include // for rename() #endif #if defined(FT_HAVE_CSTRING) # include // for strcmp(), memset(), memcpy() #elif defined(FT_HAVE_STRING_H) # include // for strcmp(), memset(), memcpy() #endif #ifdef FT_HAVE_DIRENT_H # include // for opendir(), readdir(), closedir() #endif #ifdef FT_HAVE_FCNTL_H # include // for open(), mknod() #endif #ifdef FT_HAVE_SYS_STAT_H # include // for " " , lstat(), mkdir(), mkfifo(), umask() #endif #ifdef FT_HAVE_SYS_TYPES_H # include // " " " " " " " , lseek(), ftruncate() #endif #ifdef FT_HAVE_UNISTD_H # include // " " " " ,symlink(),lchown(), close(), " " , readlink(), read(), write() #endif #ifdef FT_HAVE_SYS_STATVFS_H # include // for statvfs(), fsblkcnt_t #endif #ifdef FT_HAVE_SYS_TIME_H # include // for utimes(), utimensat() #endif #ifdef FT_HAVE_UTIME_H # include // " " " #endif #include "../assert.hh" // for ff_assert() #include "../log.hh" // for ff_log() #include "../misc.hh" // for ff_min2() #include "disk_stat.hh" // for fm_disk_stat::THRESHOLD_MIN #include "io_posix.hh" // for fm_io_posix #include "io_posix_dir.hh" // for ft_io_posix_dir #include "util_posix.hh" // for ff_posix_exec_silent() #ifndef PATH_MAX # define PATH_MAX 4096 #endif /* PATH_MAX */ FT_IO_NAMESPACE_BEGIN /** default constructor */ fm_io_posix::fm_io_posix() : super_type(), bytes_copied_since_last_check(0) { } /** destructor. calls close() */ fm_io_posix::~fm_io_posix() { close(); } /** return true if this fr_io_posix is currently (and correctly) open */ bool fm_io_posix::is_open() const { return !source_root().empty() && !target_root().empty(); } /** check for consistency and open SOURCE_ROOT, TARGET_ROOT */ int fm_io_posix::open(const fm_args & args) { int err; do { if ((err = super_type::open(args)) != 0) break; bytes_copied_since_last_check = 0; err = check_free_space(); } while (0); return err; } /** close this I/O, including file descriptors */ void fm_io_posix::close() { super_type::close(); bytes_copied_since_last_check = 0; } /** * return true if estimated free space is enough to write 'bytes_to_write' * if first_check is true, does a more conservative estimation, requiring twice more free space than normal */ bool fm_io_posix::enough_free_space(ft_uoff bytes_to_write, bool first_time) { ft_uoff half_free_space = ff_min2(source_stat().get_free(), target_stat().get_free()) >> 1; if (first_time) half_free_space >>= 1; return half_free_space > bytes_to_write && half_free_space - bytes_to_write > bytes_copied_since_last_check; } /** * add bytes_just_written to bytes_copied_since_last_check. * * if bytes_copied_since_last_check >= PERIODIC_CHECK_FREE_SPACE or >= 50% of free space, * reset bytes_copied_since_last_check to zero and call check_free_space() */ int fm_io_posix::periodic_check_free_space(ft_uoff bytes_just_written, ft_uoff bytes_to_write) { add_work_done(bytes_just_written); bytes_copied_since_last_check += bytes_just_written; int err = 0; if (!enough_free_space(bytes_to_write)) { bytes_copied_since_last_check = 0; err = check_free_space(); } return err; } /** * sync(), then call disk_stat() twice: one time on source_root() and another on target_root(). * return error if statvfs() fails or if free disk space becomes critically low */ int fm_io_posix::check_free_space() { sync(); // slow, but needed to get accurate disk stats when loop devices are involved int err = disk_stat(source_root().c_str(), source_stat()); if (err == 0) err = disk_stat(target_root().c_str(), target_stat()); return err; } /** call ::sync(). slow, but needed to get accurate disk stats when loop devices are involved */ void fm_io_posix::sync() { ::sync(); } /** * fill 'disk_stat' with information about the file-system containing 'path'. * return error if statvfs() fails or if free disk space becomes critically low */ int fm_io_posix::disk_stat(const char * path, fm_disk_stat & disk_stat) { struct statvfs buf; int err = 0; for (int i = 0; i < 2; i++) { if (::statvfs(path, & buf) != 0) return ff_log(FC_ERROR, errno, "failed to statvfs() `%s'", path); ft_uoff disk_total = (ft_uoff) buf.f_bsize * (ft_uoff) buf.f_blocks; ft_uoff disk_free = (ft_uoff) buf.f_bsize * (ft_uoff) buf.f_bfree; disk_stat.set_total(disk_total); if (i == 0 && disk_stat.is_too_low_free_space(disk_free)) { try_to_make_free_space(path); continue; } err = disk_stat.set_free(disk_free); break; } return err; } /** * use some file-system specific trickery and try to free some space. */ void fm_io_posix::try_to_make_free_space(const char * FT_ARG_UNUSED(path)) { #if 0 /* * we COULD run 'xfs_fsr ' and try to free some space on 'xfs' file-systems, * but at least on linux with an almost-full source device * xfs_fsr can WORSEN the problem by triggering 'loop write error' kernel errors, * which mean the source device has not enough space to accommodate the loop file contents. * this typically CORRUPTS the file system inside target (loop) device! */ const char * cmd = "xfs_fsr"; const char * const args[] = { cmd, path, NULL }; if (ff_posix_exec_silent(cmd, args) == 0) ff_log(FC_INFO, 0, "successfully executed '%s %s' to free some disk space", args[0], args[1]); #endif } /** * return true if 'stat' information is about a directory */ FT_INLINE static bool fm_io_posix_is_dir(const ft_stat & stat) { return S_ISDIR(stat.st_mode); } /** * return true if 'stat' information is about a regular file */ FT_INLINE static bool fm_io_posix_is_file(const ft_stat & stat) { return S_ISREG(stat.st_mode); } /** * return true if 'stat' information is about a symbolic link */ FT_INLINE static bool fm_io_posix_is_symlink(const ft_stat & stat) { return S_ISLNK(stat.st_mode); } /** core of recursive move algorithm, actually moves the whole source tree into target */ int fm_io_posix::move() { if (move_rename(source_root().c_str(), target_root().c_str()) == 0) return 0; /* avoid messing up permissions of created files/directories/special-devices */ umask(0); int err = init_work(); if (err == 0) err = move(source_root(), target_root()); if (err == 0) ff_log(FC_NOTICE, 0, "job completed."); return err; } /** * move a single file/socket/special-device or a whole directory tree */ int fm_io_posix::move(const ft_string & source_path, const ft_string & target_path) { ft_stat stat; const std::set & exclude_set = this->exclude_set(); int err = 0; ff_log(FC_DEBUG, 0, "`%s'\t-> `%s'", source_path.c_str(), target_path.c_str()); do { if (exclude_set.count(source_path) != 0) { ff_log(FC_INFO, 0, "skipped `%s', matches exclude list", source_path.c_str()); break; } if ((err = this->stat(source_path, stat)) != 0) break; if (fm_io_posix_is_file(stat)) { err = this->move_file(source_path, stat, target_path); break; } else if (!fm_io_posix_is_dir(stat)) { err = this->move_special(source_path, stat, target_path); break; } ft_io_posix_dir source_dir; if ((err = source_dir.open(source_path))) break; /* * we allow target_root() to exist already, but other target directories must NOT exist. * option '-f' drops this check, i.e. any target directory can exist already * * Exception: we allow a 'lost+found' directory to exist inside target_root() */ if ((err = this->create_dir(target_path)) != 0) break; if ((err = this->periodic_check_free_space()) != 0) break; ft_string child_source = source_path, child_target = target_path; child_source += '/'; child_target += '/'; ft_io_posix_dirent * dirent; /* recurse on directory contents */ while ((err = source_dir.next(dirent)) == 0 && dirent != NULL) { /* skip "." and ".." */ if (!strcmp(".", dirent->d_name) || !strcmp("..", dirent->d_name)) continue; child_source.resize(1 + source_path.size()); // faster than child_source = source_path + '/' child_source += dirent->d_name; child_target.resize(1 + target_path.size()); // faster than child_target = target_path + '/' child_target += dirent->d_name; if ((err = this->move(child_source, child_target)) != 0) break; } if (err != 0) break; if ((err = this->copy_stat(target_path.c_str(), stat)) != 0) break; /* * we do not delete 'lost+found' directory inside source_root() */ if ((err = this->remove_dir(source_path)) != 0) break; } while (0); return err; } /** * fill 'stat' with information about the file/directory/special-device 'path' */ int fm_io_posix::stat(const ft_string & path, ft_stat & stat) { const char * str = path.c_str(); int err = 0; if (lstat(str, & stat) != 0) err = ff_log(FC_ERROR, errno, "failed to lstat() `%s'", str); return err; } /** * move the special-device 'source_path' to 'target_path'. */ int fm_io_posix::move_special(const ft_string & source_path, const ft_stat & stat, const ft_string & target_path) { const char * source = source_path.c_str(), * target = target_path.c_str(); int err = 0; ff_log(FC_TRACE, 0, "move_special() `%s'\t-> `%s'", source, target); if (simulate_run()) return err; do { /* check inode_cache for hard links and recreate them */ err = this->hard_link(stat, target_path); if (err == 0) { /** hard link succeeded, no need to create the special-device */ err = this->periodic_check_free_space(); break; } else if (err == EAGAIN) { /* no luck with inode_cache, proceed as usual */ err = 0; } else { /** hard link() failed */ return err; } /* found a special device */ if (S_ISCHR(stat.st_mode) || S_ISBLK(stat.st_mode) || S_ISSOCK(stat.st_mode)) { if (mknod(target, (stat.st_mode | 0600) & ~0077, stat.st_rdev) != 0) { if (!S_ISSOCK(stat.st_mode)) { err = ff_log(FC_ERROR, errno, "failed to create target special device `%s'", target); break; } ff_log(FC_WARN, errno, "failed to create target UNIX socket `%s'", target); } } else if (S_ISFIFO(stat.st_mode)) { if (mkfifo(target, 0600) != 0) { err = ff_log(FC_ERROR, errno, "failed to create target named pipe `%s'", target); break; } } else if (fm_io_posix_is_symlink(stat)) { char link_to[PATH_MAX+1]; ssize_t link_len = readlink(source, link_to, PATH_MAX); if (link_len == -1) { err = ff_log(FC_ERROR, errno, "failed to read source symbolic link `%s'", source); break; } link_to[link_len] = '\0'; if (symlink(link_to, target) != 0) { err = ff_log(FC_ERROR, errno, "failed to create target symbolic link `%s'\t-> `%s'", target, link_to); break; } } else { ff_log(FC_ERROR, 0, "special device %s has unknown type 0%" FT_OLL ", cannot create it", source, (ft_ull)(stat.st_mode & ~07777)); err = -EOPNOTSUPP; break; } if ((err = this->copy_stat(target, stat)) != 0) break; if ((err = this->periodic_check_free_space()) != 0) break; } while (0); if (err == 0) err = remove_special(source); return err; } /** * remove the special file 'source_path' */ int fm_io_posix::remove_special(const char * source_path) { int err = 0; if (::remove(source_path) != 0) err = ff_log(FC_ERROR, errno, "failed to remove source special device `%s'", source_path); return err; } /** * remove the regular file 'source_path' */ int fm_io_posix::remove_file(const char * source_path) { int err = 0; if (::remove(source_path) != 0) err = ff_log(FC_ERROR, errno, "failed to remove source file `%s'", source_path); return err; } /** * move the regular file 'source_path' to 'target_path'. */ int fm_io_posix::move_file(const ft_string & source_path, const ft_stat & stat, const ft_string & target_path) { const char * source = source_path.c_str(), * target = target_path.c_str(); int err = 0; ff_log(FC_TRACE, 0, "move_file() `%s'\t-> `%s'", source, target); if (simulate_run()) return err; /* check inode_cache for hard links and recreate them */ err = this->hard_link(stat, target_path); if (err == 0) { /** hard link succeeded, no need to copy the file contents */ err = this->periodic_check_free_space(); goto move_file_remove_source; } else if (err != EAGAIN) { /** hard link failed */ return err; } /* no luck with inode_cache, proceed as usual */ err = copy_file_contents(source_path, stat, target_path); move_file_remove_source: if (err == 0) err = remove_file(source); return err; } /** * copy the contents of regular file 'source_path' to 'target_path'. */ int fm_io_posix::copy_file_contents(const ft_string & source_path, const ft_stat & stat, const ft_string & target_path) { const char * source = source_path.c_str(), * target = target_path.c_str(); int err = 0; int in_fd = ::open(source, O_RDWR); if (in_fd < 0) err = ff_log(FC_ERROR, errno, "failed to open source file `%s'", source); #ifndef O_EXCL # define O_EXCL 0 #endif int out_fd = ::open(target, O_CREAT|O_WRONLY|O_TRUNC|O_EXCL, 0600); if (out_fd < 0) err = ff_log(FC_ERROR, errno, "failed to create target file `%s'", target); if (err == 0) { err = this->periodic_check_free_space(); if (err == 0) err = this->copy_stream(in_fd, out_fd, stat, source, target); } if (in_fd >= 0) (void) ::close(in_fd); if (out_fd >= 0) (void) ::close(out_fd); if (err == 0) err = this->copy_stat(target, stat); return err; } /** * try to rename a file, directory or special-device from 'source_path' to 'target_path'. */ int fm_io_posix::move_rename(const char * source, const char * target) { int err = 0; do { if (simulate_run()) { err = EXDEV; break; } if (::rename(source, target) != 0) { err = errno; break; } ff_log(FC_TRACE, 0, "move_rename() `%s'\t-> `%s': success", source, target); } while (0); return err; } /** * check inode_cache for hard links and recreate them. * must be called if and only if stat.st_nlink > 1 * * returns EAGAIN if inode *was* not in inode_cache */ int fm_io_posix::hard_link(const ft_stat & stat, const ft_string & target_path) { ft_string cached_link = target_path; int err; if (stat.st_nlink > 1) { /* * source path has 2 or more links. * check if it is cached already, or add it to detect further links to the same file/device */ err = inode_cache_find_or_add(stat.st_ino, cached_link); } else { /* * source path has only 1 link. it can be either: * a) the last link of a file/device which previously had multiple links, * but we all other links during fm_io_posix::move() * b) a file/device which always had one link * * so we check for its presence in inode_cache, but we do not add it to inode_cache * in any case, if a cached inode is found, we erase it * because it is guaranteed that no more links to this inode will ever be found. */ err = inode_cache_find_and_delete(stat.st_ino, cached_link); } if (err == 0) { // fake error to tell caller that inode was not in cache err = EAGAIN; } else if (err == 1) { // inode found in cache const char * link_to = cached_link.c_str(), * link_from = target_path.c_str(); if (::link(link_to, link_from) != 0) err = ff_log(FC_ERROR, errno, "failed to create target hard link `%s'\t-> `%s'", link_from, link_to); else err = 0; } return err; } enum { FT_LOG_BUFSIZE = 16, //< log2(FT_BUFSIZE) // FT_BUFSIZE must be a power of 2 (currently 64k), // and must be somewhat smaller than fm_disk_stat::THRESHOLD_MIN (currently 96k) FT_BUFSIZE = (ft_size)1 << FT_LOG_BUFSIZE, FT_BUFSIZE_m1 = FT_BUFSIZE - 1, FT_BUFSIZE_SANITY_CHECK = sizeof(char[FT_BUFSIZE * 3 / 2 >= fm_disk_stat::THRESHOLD_MIN ? 1 : -1]) }; /** * forward or backward copy file/stream contents from in_fd to out_fd. * * if disk space is low, we copy backward and progressively truncate in_fd to conserve space: * results in heavy fragmentation on target file, but at least we can continue */ int fm_io_posix::copy_stream(int in_fd, int out_fd, const ft_stat & stat, const char * source, const char * target) { ft_off file_size = stat.st_size; int err; if ((err = periodic_check_free_space(0, file_size)) != 0) return err; if (enough_free_space(file_size)) { /* enough free space, use normal forward copy */ return copy_stream_forward(in_fd, out_fd, source, target); } /* not enough free space, use backward copy + progressively truncate source file */ double pretty_size = 0.0; const char * pretty_label = ff_pretty_size((ft_uoff) file_size, & pretty_size); ff_log(FC_INFO, 0, "using backward copy and truncate for file `%s': less than %.2f %sbytes free space left", target, pretty_size, pretty_label); if (::lseek(in_fd, 0, SEEK_END) != file_size) return ff_log(FC_ERROR, errno, "error seeking to end of file `%s'", source); ft_off offset_high = file_size, offset_low; if ((err = fd_truncate(out_fd, offset_high, target)) != 0) return err; // slow, but on Linux not doing it is worse: // you can get inaccurate disk usage statistics // and (if loop device becomes full) silent I/O errors! sync(); char buf[FT_BUFSIZE]; ft_size expected, got; ft_size hole_len, nonhole_len, tosend_offset, tosend_left; while (offset_high > 0) { /** truncate in_fd, discarding any data that we already copied */ if ((err = fd_truncate(in_fd, offset_high, source)) != 0) break; offset_low = (offset_high - 1) & ~(ft_off)FT_BUFSIZE_m1; ff_assert(offset_high - offset_low <= FT_BUFSIZE); got = expected = (ft_size)(offset_high - offset_low); if ((err = fd_seek2(in_fd, out_fd, offset_low, source, target)) != 0) break; if ((err = this->full_read(in_fd, buf, got, source)) != 0 || got != expected) { if (err == 0) { ff_log(FC_ERROR, 0, "error reading from `%s': expected %" FT_ULL " bytes, got %" FT_ULL " bytes", source, (ft_ull)expected, (ft_ull)got); err = -EIO; } break; } tosend_offset = 0; for (tosend_left = got; tosend_left != 0; ) { /* detect hole */ if ((hole_len = hole_length(buf + tosend_offset, tosend_left)) != 0) { /* re-create hole in target file */ if (::lseek(out_fd, (ft_off)hole_len, SEEK_CUR) == (ft_off)-1) { err = ff_log(FC_ERROR, errno, "error seeking %" FT_ULL " bytes forward in file `%s'", (ft_ull)hole_len, target); break; } tosend_offset += hole_len; tosend_left -= hole_len; } if ((nonhole_len = nonhole_length(buf + tosend_offset, tosend_left)) != 0) { // copy the non-hole data if ((err = this->full_write(out_fd, buf + tosend_offset, nonhole_len, target)) != 0) break; tosend_offset += nonhole_len; tosend_left -= nonhole_len; } } if (err != 0) break; offset_high = offset_low; } if (err != 0 && offset_high != 0 && offset_high != file_size) { ff_log(FC_ERROR, 0, "DANGER! due to previous error, copying `%s' -> `%s' was aborted", source, target); ff_log(FC_ERROR, 0, " and BOTH copies of this file are now incomplete."); ff_log(FC_ERROR, 0, " To recover this file, execute the following command"); ff_log(FC_ERROR, 0, " AFTER freeing enough space in the source device:"); offset_high >>= FT_LOG_BUFSIZE; ff_log(FC_ERROR, 0, " /bin/dd bs=%" FT_ULL " skip=%" FT_ULL " seek=%" FT_ULL " conv=notrunc if=\"%s\" of=\"%s\"", (ft_ull)FT_BUFSIZE, (ft_ull)offset_high, (ft_ull)offset_high, target, source); } return err; } /** * forward copy file/stream contents from in_fd to out_fd. */ int fm_io_posix::copy_stream_forward(int in_fd, int out_fd, const char * source, const char * target) { char buf[FT_BUFSIZE]; ft_size present = 0, present_aligned, got; ft_size hole_len, nonhole_len, tosend_offset, tosend_left; int err = 0; for (;;) { got = FT_BUFSIZE - present; if ((err = this->full_read(in_fd, buf + present, got, source)) != 0 || got == 0) break; tosend_left = present_aligned = (present += got) / APPROX_BLOCK_SIZE * APPROX_BLOCK_SIZE; for (tosend_offset = 0; tosend_left != 0;) { /* detect hole */ if ((hole_len = hole_length(buf + tosend_offset, tosend_left)) != 0) { /* re-create hole in target file */ if (::lseek(out_fd, (ft_off)hole_len, SEEK_CUR) == (ft_off)-1) { err = ff_log(FC_ERROR, errno, "error seeking in file `%s'", target); break; } tosend_offset += hole_len; tosend_left -= hole_len; } if ((nonhole_len = nonhole_length(buf + tosend_offset, tosend_left)) != 0) { // copy the non-hole data if ((err = this->full_write(out_fd, buf + tosend_offset, nonhole_len, target)) != 0) break; tosend_offset += nonhole_len; tosend_left -= nonhole_len; } } if (err != 0) break; if (present_aligned != 0 && present > present_aligned) // move any remaining unaligned fragment to buffer beginning ::memmove(buf, buf + present_aligned, present - present_aligned); present -= present_aligned; present_aligned = 0; } if (err == 0) do { if (present > present_aligned) { // write any remaining unaligned fragment err = this->full_write(out_fd, buf + present_aligned, present - present_aligned, target); break; } // file may end with a hole... handle this case correctly! ft_off filelen = ::lseek(out_fd, (ft_off)0, SEEK_CUR); if (filelen == (ft_off)-1) { err = ff_log(FC_ERROR, errno, "error seeking in file `%s'", target); break; } if ((err = fd_truncate(out_fd, filelen, target)) != 0) break; } while (0); return err; } /** * truncate file pointed by descriptor to specified length */ int fm_io_posix::fd_truncate(int fd, ft_off length, const char * path) { int err = 0; if (::ftruncate(fd, length) == -1) err = ff_log(FC_ERROR, errno, "error truncating file `%s' to %" FT_ULL " bytes", path, (ft_ull)length); return err; } /** * seek to specified position of *both* fd1 and fd2 */ int fm_io_posix::fd_seek2(int fd1, int fd2, ft_off offset, const char * path1, const char * path2) { int err = fd_seek(fd1, offset, path1); if (err == 0) err = fd_seek(fd2, offset, path2); return err; } /** * seek to specified position of file descriptor */ int fm_io_posix::fd_seek(int fd, ft_off offset, const char * path) { int err = 0; if (::lseek(fd, offset, SEEK_SET) != offset) err = ff_log(FC_ERROR, errno, "error seeking to position %" FT_ULL " of file `%s'", (ft_ull)offset, path); return err; } /** * scan memory for blocksize-length and blocksize-aligned sections full of zeroes * return length of zeroed area at the beginning of scanned memory. * returned length is rounded down to block_size */ size_t fm_io_posix::hole_length(const char * mem, ft_size mem_len) { size_t len = 0; /* blocks smaller than APPROX_BLOCK_SIZE are always considered non-hole */ mem_len = (mem_len / APPROX_BLOCK_SIZE) * APPROX_BLOCK_SIZE; for (; len < mem_len; len++) if (mem[len] != '\0') break; return (len / APPROX_BLOCK_SIZE) * APPROX_BLOCK_SIZE; } /** * scan memory for blocksize-length and blocksize-aligned sections NOT full of zeroes * return length of NON-zeroed area at the beginning of scanned memory. * returned length is rounded UP to block_size if it fits mem_len */ size_t fm_io_posix::nonhole_length(const char * mem, ft_size mem_len) { size_t hole_len, offset = 0; while (mem_len >= APPROX_BLOCK_SIZE && (hole_len = hole_length(mem + offset, APPROX_BLOCK_SIZE)) == 0) { offset += APPROX_BLOCK_SIZE; mem_len -= APPROX_BLOCK_SIZE; } /* * blocks smaller than APPROX_BLOCK_SIZE, * or final fragments smaller than APPROX_BLOCK_SIZE, * are always considered non-hole */ if (mem_len < APPROX_BLOCK_SIZE) offset += mem_len; return offset; } /** * read bytes from in_fd, retrying in case of short reads or interrupted system calls. * returns 0 for success, else error. * on return, len will contain the number of bytes actually read */ int fm_io_posix::full_read(int in_fd, char * data, ft_size & len, const char * source_path) { ft_size got, left = len; int err = 0; while (left) { while ((got = ::read(in_fd, data, len)) == (ft_size)-1 && errno == EINTR) ; if (got == 0 || got == (ft_size)-1) { if (got != 0) err = ff_log(FC_ERROR, errno, "error reading from `%s'", source_path); // else got == 0: end-of-file break; } left -= got; data += got; } len -= left; return err; } /** * write bytes to out_fd, retrying in case of short writes or interrupted system calls. * returns 0 for success, else error */ int fm_io_posix::full_write(int out_fd, const char * data, ft_size len, const char * target_path) { ft_size chunk; int err = 0; while (len) { while ((chunk = ::write(out_fd, data, len)) == (ft_size)-1 && errno == EINTR) ; if (chunk == 0 || chunk == (ft_size)-1) { err = ff_log(FC_ERROR, errno, "error writing to `%s'", target_path); break; } data += chunk; len -= chunk; if ((err = this->periodic_check_free_space(chunk)) != 0) break; } return err; } /** * copy the permission bits, owner/group and timestamps from 'stat' to 'target' */ int fm_io_posix::copy_stat(const char * target, const ft_stat & stat) { int err = 0; if (simulate_run()) return err; const char * label = fm_io_posix_is_dir(stat) ? "directory" : fm_io_posix_is_file(stat) ? "file" : "special device"; /* copy timestamps */ #if defined(FT_HAVE_UTIMENSAT) && defined(AT_FDCWD) && defined(AT_SYMLINK_NOFOLLOW) do { struct timespec time_buf[2]; time_buf[0].tv_sec = stat.st_atime; time_buf[1].tv_sec = stat.st_mtime; # if defined(FT_HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC) time_buf[0].tv_nsec = stat.st_atim.tv_nsec; # elif defined(FT_HAVE_STRUCT_STAT_ST_ATIMENSEC) time_buf[0].tv_nsec = stat.st_atimensec; # endif # if defined(FT_HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) time_buf[1].tv_nsec = stat.st_mtim.tv_nsec; # elif defined(FT_HAVE_STRUCT_STAT_ST_MTIMENSEC) time_buf[1].tv_nsec = stat.st_mtimensec; # endif if (utimensat(AT_FDCWD, target, time_buf, AT_SYMLINK_NOFOLLOW) != 0) ff_log(FC_WARN, errno, "cannot change timestamps on %s `%s'", label, target); } while (0); #elif defined(FT_HAVE_UTIMES) /* utimes() does not work on symbolic links */ if (!fm_io_posix_is_symlink(stat)) { struct timeval time_buf[2]; time_buf[0].tv_sec = stat.st_atime; time_buf[1].tv_sec = stat.st_mtime; time_buf[0].tv_usec = time_buf[1].tv_usec = 0; if (utimes(target, time_buf) != 0) ff_log(FC_WARN, errno, "cannot change timestamps on %s `%s'", label, target); } #else # warning utimensat() and utimes() are both missing. fsmove will not be able to set timestamps of copied files/directories #endif do { bool is_error = !force_run(); bool is_symlink = fm_io_posix_is_symlink(stat); const char * fail_label = is_error ? "failed to" : "cannot"; /* copy owner and group. this resets any SUID bits */ #if defined(FT_HAVE_LCHOWN) if (lchown(target, stat.st_uid, stat.st_gid) != 0) #else if (!is_symlink && chown(target, stat.st_uid, stat.st_gid) != 0) #endif { err = ff_log(is_error ? FC_ERROR : FC_WARN, errno, "%s set owner=%" FT_ULL " and group=%" FT_ULL " on %s `%s'", fail_label, (ft_ull)stat.st_uid, (ft_ull)stat.st_gid, label, target); if (is_error) break; err = 0; } /* * copy permission bits * 1. chmod() on a symbolic link has no sense, don't to it * 2. chmod() must be performed AFTER lchown(), because lchown() resets any SUID bits */ if (!is_symlink && chmod(target, stat.st_mode) != 0) { err = ff_log(is_error ? FC_ERROR : FC_WARN, errno, "%s change mode to 0%" FT_OLL " on %s `%s'", fail_label, (ft_ull)stat.st_mode, label, target); if (is_error) break; err = 0; } } while (0); return err; } /** * return true if path is the target directory lost+found. * Treated specially because it is emptied but not removed. */ bool fm_io_posix::is_source_lost_found(const ft_string & path) const { return path == source_root() + "/lost+found"; } /** * return true if path is the target directory lost+found. * Treated specially because it is allowed to exist already. */ bool fm_io_posix::is_target_lost_found(const ft_string & path) const { return path == target_root() + "/lost+found"; } /** create a target directory, copying its mode and other meta-data from 'stat' */ int fm_io_posix::create_dir(const ft_string & path) { const char * dir = path.c_str(); int err = 0; ff_log(FC_TRACE, 0, "create_dir() `%s'", dir); do { if (simulate_run()) break; if (::mkdir(dir, 0700) == 0) break; /* if creating target root, ignore EEXIST error: target root is allowed to exist already */ if ((err = errno) != EEXIST || path != target_root()) { /* if force_run(), always ignore EEXIST error: any target directory is allowed to exist already */ /* in any case, we also allow target directory lost+found to exist already */ bool is_warn = err == EEXIST && (force_run() || is_target_lost_found(path)); err = ff_log(is_warn ? FC_WARN : FC_ERROR, err, "failed to create target directory `%s'", dir); if (!is_warn) break; } err = 0; } while (0); return err; } /** * remove a source directory. * exception: we do not delete 'lost+found' directory inside source_root() */ int fm_io_posix::remove_dir(const ft_string & path) { const char * dir = path.c_str(); int err = 0; ff_log(FC_TRACE, 0, "remove_dir() `%s'", dir); do { if (simulate_run() || is_source_lost_found(path)) break; if (::remove(dir) != 0) { /* ignore error if we are removing source root: it is allowed to be in use */ if (path != source_root()) { /* if force_run(), failure to remove a source directory is just a warning */ bool is_warn = force_run(); err = ff_log(is_warn ? FC_WARN : FC_ERROR, errno, "%sfailed to remove source directory `%s'", is_warn ? "warning: " : "", dir); if (!is_warn) break; err = 0; } break; } } while (0); return err; } FT_IO_NAMESPACE_END fstransform-0.9.4/fsmove/src/io/io_posix.hh000066400000000000000000000211011345021500300207230ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/io_posix.hh * * Created on: Sep 22, 2011 * Author: max */ #ifndef FSMOVE_IO_IO_POSIX_HH #define FSMOVE_IO_IO_POSIX_HH #include "../types.hh" // for ft_string */ #include "io.hh" // for fm_io */ FT_IO_NAMESPACE_BEGIN /** * class performing I/O on POSIX systems */ class fm_io_posix: public fm_io { private: typedef fm_io super_type; ft_uoff bytes_copied_since_last_check; enum { /** * APPROX_BLOCK_SIZE is an approximated block size, only used for tuning creation of holes. * No need for it to be the exact block size used by the source and target file systems */ APPROX_BLOCK_SIZE = 4096, /** * APPROX_INODE_COST is an approximated disk space used by an inode * (directory, file or special device) even if it contains no actual data. */ APPROX_INODE_COST = 256, }; /** * return true if estimated free space is comfortably high enough to write 'bytes_to_write' * if first_check is true, does a more conservative estimation, requiring twice more free space than normal */ bool enough_free_space(ft_uoff bytes_to_write = 0, bool first_check = false); /** * call sync(), then call disk_stat() twice: one time on source_root() and another on target_root(). * return error if statvfs() fails or if free disk space becomes critically low */ int check_free_space(); /** * fill 'disk_stat' with information about the file-system containing 'path'. * return error if statvfs() fails or if free disk space becomes critically low */ int disk_stat(const char * path, fm_disk_stat & disk_stat); /** * use some file-system specific trickery to try and free some space. * currently, it runs 'xfs_fsr ' which can free some space on 'xfs' file-systems */ void try_to_make_free_space(const char * path); /** * fill 'stat' with information about the file/directory/special-device 'path' */ int stat(const ft_string & path, ft_stat & stat); /** * move a single file/socket/device or a whole directory tree */ int move(const ft_string & source_path, const ft_string & target_path); /** * try to rename a file, directory or special-device from 'source_path' to 'target_path'. */ int move_rename(const char * source, const char * target); /** * move the single regular file 'source_path' to 'target_path'. */ int move_file(const ft_string & source_path, const ft_stat & source_stat, const ft_string & target_path); /** * move the single special-device 'source_path' to 'target_path'. */ int move_special(const ft_string & source_path, const ft_stat & source_stat, const ft_string & target_path); /** * move the single directory 'source_path' to 'target_path'. */ int move_dir(const ft_string & source_path, const ft_stat & source_stat, const ft_string & target_path); /** * forward or backward copy file/stream contents from in_fd to out_fd. * * if disk space is low, we copy backward and progressively truncate in_fd to conserve space: * results in heavy fragmentation on target file, but at least we can continue */ int copy_stream(int in_fd, int out_fd, const ft_stat & stat, const char * source, const char * target); /** * forward copy file/stream contents from in_fd to out_fd. */ int copy_stream_forward(int in_fd, int out_fd, const char * source, const char * target); /** * truncate file pointed by descriptor to specified length */ int fd_truncate(int fd, ft_off length, const char * path); /** * seek to specified position of file descriptor */ int fd_seek(int fd, ft_off offset, const char * path); /** * seek to specified position of *both* file descriptors fd1 and fd2 */ int fd_seek2(int fd1, int fd2, ft_off offset, const char * path1, const char * path2); /** * scan memory for blocksize-length and blocksize-aligned sections full of zeroes * return length of zeroed area at the beginning of scanned memory. * returned length is rounded down to block_size */ static size_t hole_length(const char * mem, ft_size mem_len); /** * scan memory for blocksize-length and blocksize-aligned sections NOT full of zeroes * return length of NON-zeroed area at the beginning of scanned memory. * returned length is rounded UP to block_size */ static size_t nonhole_length(const char * mem, ft_size mem_len); /** * read bytes from in_fd, retrying in case of short reads or interrupted system calls. * returns 0 for success, else error * on return, len will contain the number of bytes actually read */ int full_read(int in_fd, char * data, ft_size & len, const char * source_path); /** * write bytes to out_fd, retrying in case of short writes or interrupted system calls. * returns 0 for success, else error */ int full_write(int out_fd, const char * data, ft_size len, const char * target_path); /** * check inode_cache for hard links and recreate them. * must be called if and only if stat.st_nlink > 1. * * returns EAGAIN if inode was not in inode_cache */ int hard_link(const ft_stat & stat, const ft_string & target_path); /** create a target directory */ int create_dir(const ft_string & path); /** * return true if path is the source directory lost+found. * Treated specially because it is emptied but not removed. */ bool is_source_lost_found(const ft_string & path) const; /** * return true if path is the target directory lost+found. * Treated specially because it is allowed to exist already. */ bool is_target_lost_found(const ft_string & path) const; protected: /** call ::sync(). slow, but needed to get accurate disk stats when loop devices are involved */ virtual void sync(); /** * add bytes_just_written to bytes_copied_since_last_check. * * if enough_free_space() returns false, * also call check_free_space() and reset bytes_copied_since_last_check to zero */ int periodic_check_free_space(ft_uoff bytes_just_written = APPROX_INODE_COST, ft_uoff bytes_to_write = 0); /** * copy the permission bits, owner/group and timestamps from 'stat' to 'target' */ int copy_stat(const char * target, const ft_stat & stat); /** * copy the contents of single regular file 'source_path' to 'target_path'. */ virtual int copy_file_contents(const ft_string & source_path, const ft_stat & source_stat, const ft_string & target_path); /** * remove a regular file inside source directory */ virtual int remove_file(const char * source_path); /** * remove a special file inside source directory */ virtual int remove_special(const char * source_path); /** * remove a source directory, which must be empty * exception: will not remove '/lost+found' directory inside source_root() */ virtual int remove_dir(const ft_string & path); public: /** constructor */ fm_io_posix(); /** destructor. calls close() */ virtual ~fm_io_posix(); /** return true if this fr_io_posix is currently (and correctly) open */ virtual bool is_open() const; /** check for consistency and open SOURCE_ROOT, TARGET_ROOT */ virtual int open(const fm_args & args); /** core of recursive move algorithm, actually moves the whole source tree into target */ virtual int move(); /** close this I/O, including file descriptors to DEVICE, LOOP-FILE, ZERO-FILE and SECONDARY-STORAGE */ virtual void close(); }; FT_IO_NAMESPACE_END #endif /* FSMOVE_IO_IO_POSIX_HH */ fstransform-0.9.4/fsmove/src/io/io_posix_dir.cc000077700000000000000000000000001345021500300302412../../../fsremap/src/io/io_posix_dir.ccustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/io/io_posix_dir.hh000077700000000000000000000000001345021500300302652../../../fsremap/src/io/io_posix_dir.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/io/io_prealloc.cc000066400000000000000000000107541345021500300213640ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/io_prealloc.cc * * Created on: Apr 15, 2012 * Author: max */ #include "../first.hh" #if defined(FT_HAVE_CERRNO) # include // for errno and error codes #elif defined(FT_HAVE_ERRNO_H) # include #endif #ifdef FT_HAVE_FCNTL_H #include // for open(), fallocate() #endif #ifdef FT_HAVE_SYS_STAT_H # include // for " #endif #ifdef FT_HAVE_SYS_TYPES_H # include // for " #endif #ifdef FT_HAVE_UNISTD_H # include // for close() #endif #include "../log.hh" // for ff_log() #include "io_prealloc.hh" // for fm_io_prealloc, FT_HAVE_FM_IO_IO_PREALLOC #ifdef FT_HAVE_FM_IO_IO_PREALLOC FT_IO_NAMESPACE_BEGIN /** default constructor. */ fm_io_prealloc::fm_io_prealloc() : super_type() { } /** destructor. */ fm_io_prealloc::~fm_io_prealloc() { } /** check for consistency and open SOURCE_ROOT, TARGET_ROOT */ int fm_io_prealloc::open(const fm_args & args) { int err = super_type::open(args); if (err == 0) progress_msg(" still to preallocate"); return err; } /** * does nothing: fr_io_prealloc never needs to ::sync(). */ void fm_io_prealloc::sync() { } /** * remove the regular file 'source_path' * Since we are preallocating, we can (and will) avoid any modification * to the source file system. Thus this method does nothing. */ int fm_io_prealloc::remove_file(const char * FT_ARG_UNUSED(source_path)) { return 0; } /** * remove the special file 'source_path' * Since we are preallocating, we can (and will) avoid any modification * to the source file system. Thus this method does nothing. */ int fm_io_prealloc::remove_special(const char * FT_ARG_UNUSED(source_path)) { return 0; } /** * remove a source directory. * exception: we are not supposed to delete 'lost+found' directory inside source_root() * Since we are preallocating, we can (and will) avoid any modification * to the source file system. Thus this method does nothing. */ int fm_io_prealloc::remove_dir(const ft_string & path) { ff_log(FC_TRACE, 0, "remove_dir() `%s'", path.c_str()); return 0; } /** * copy the contents of regular file 'source_path' to 'target_path'. * Since we are preallocating, we just preallocate enough blocks inside 'target_path' */ int fm_io_prealloc::copy_file_contents(const ft_string & FT_ARG_UNUSED(source_path), const ft_stat & source_stat, const ft_string & target_path) { const char * target = target_path.c_str(); int err = 0; #ifndef O_EXCL # define O_EXCL 0 #endif int out_fd = ::open(target, O_CREAT|O_WRONLY|O_TRUNC|O_EXCL, 0600); if (out_fd < 0) err = ff_log(FC_ERROR, errno, "failed to create target file `%s'", target); if (err == 0) { err = this->periodic_check_free_space(); if (err == 0) { ft_off len = source_stat.st_size; // we ONLY want REAL preallocation: avoid posix_fallocate(), // as it will happily write a bunch of zeroes in target file if REAL real preallocation is not supported, // spoiling our purpose of NOT increasing disk usage of the loop file we are writing into if (len == 0 || fallocate(out_fd, 0, 0, len) == 0) err = this->periodic_check_free_space(len); else err = ff_log(FC_ERROR, errno, "failed to preallocate %" FT_ULL " bytes for target file '%s': error in fallocate()", (ft_ull) len, target); } } if (out_fd >= 0) (void) ::close(out_fd); if (err == 0) err = this->copy_stat(target, source_stat); return err; } FT_IO_NAMESPACE_END #endif /* FT_HAVE_FM_IO_IO_PREALLOC */ fstransform-0.9.4/fsmove/src/io/io_prealloc.hh000066400000000000000000000061101345021500300213650ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/io_prealloc.hh * * Created on: Apr 15, 2012 * Author: max */ #ifndef FSMOVE_IO_IO_PREALLOC_HH #define FSMOVE_IO_IO_PREALLOC_HH #include "../types.hh" // for ft_string, FT_HAVE_FALLOCATE #include "io_posix.hh" // for fm_io_posix // io_prealloc requires fallocate() #ifdef FT_HAVE_FALLOCATE # define FT_HAVE_FM_IO_IO_PREALLOC FT_IO_NAMESPACE_BEGIN /** * class performing I/O on POSIX systems with preallocation. * performs target files preallocation WITHOUT modifying the source file directory */ class fm_io_prealloc: public fm_io_posix { private: typedef fm_io_posix super_type; protected: /** * does nothing: fr_io_prealloc never needs to ::sync(). */ virtual void sync(); /** * copy the contents of single regular file 'source_path' to 'target_path'. * Since we are preallocating, we just preallocate enough blocks inside 'target_path' */ virtual int copy_file_contents(const ft_string & source_path, const ft_stat & source_stat, const ft_string & target_path); /** * remove a regular file inside source directory * Since we are preallocating, we can (and will) avoid any modification * to the source file system. Thus this method does nothing. */ virtual int remove_file(const char * source_path); /** * remove a special file inside source directory * Since we are preallocating, we can (and will) avoid any modification * to the source file system. Thus this method does nothing. */ virtual int remove_special(const char * source_path); /** * remove a source directory, which must be empty * exception: will not remove '/lost+found' directory inside source_root() * Since we are preallocating, we can (and will) avoid any modification * to the source file system. Thus this method does nothing. */ virtual int remove_dir(const ft_string & path); public: /** default constructor. */ fm_io_prealloc(); /** check for consistency and open SOURCE_ROOT, TARGET_ROOT */ virtual int open(const fm_args & args); /** destructor. */ virtual ~fm_io_prealloc(); }; FT_IO_NAMESPACE_END #endif /* FT_HAVE_FM_IO_IO_PREALLOC */ #endif /* FSMOVE_IO_IO_PREALLOC_HH */ fstransform-0.9.4/fsmove/src/io/util_dir.cc000077700000000000000000000000001345021500300265112../../../fsremap/src/io/util_dir.ccustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/io/util_dir.hh000077700000000000000000000000001345021500300265352../../../fsremap/src/io/util_dir.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/io/util_posix.cc000066400000000000000000000076531345021500300212770ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/util_posix.cc * * Created on: Mar 27, 2012 * Author: max */ #include "../first.hh" #if defined(FT_HAVE_ERRNO_H) # include // for errno, ECHILD #elif defined(FT_HAVE_CERRNO) # include // for errno, ECHILD #endif #if defined(FT_HAVE_STDLIB_H) # include // for exit() #elif defined(FT_HAVE_CSTDLIB) # include // for exit() #endif #ifdef FT_HAVE_UNISTD_H # include // for dup2(), close(), fork(), execvp() #endif #ifdef FT_HAVE_FCNTL_H # include // for open() #endif #ifdef FT_HAVE_SYS_TYPES_H # include // for " , waitpid() #endif #ifdef FT_HAVE_SYS_STAT_H # include // for " #endif #ifdef FT_HAVE_SYS_WAIT_H # include // for waitpid() #endif #include "../log.hh" // for ff_log() #include "util_posix.hh" // for ff_posix_exec_silent() FT_IO_NAMESPACE_BEGIN /** * spawn a system command, typically with fork()+execv(), wait for it to complete and return its exit status. * argv[0] is conventionally the program name. * argv[1...] are program arguments and must be terminated with a NULL pointer. */ int ff_posix_exec_silent(const char * path, const char * const argv[]) { int err; pid_t pid = ::fork(); if (pid == 0) { /* child */ int dev_null = ::open("/dev/null", O_RDWR); if (dev_null >= 0) { (void) ::dup2(dev_null, 0); (void) ::dup2(dev_null, 1); (void) ::dup2(dev_null, 2); if (dev_null > 2) (void) ::close(dev_null); } else ff_log(FC_DEBUG, errno, "open('/dev/null') failed"); ::execvp(path, (char * const *)argv); /* if we reach here, execvp() failed! */ ff_log(FC_DEBUG, err = errno, "execvp(%s) failed"); /* exit() can only return one-byte exit status */ err &= 0xff; if (err == 0) { err = (ECHILD > 0 ? ECHILD : -ECHILD) & 0xff; if (err == 0) err = 1; } ::exit(err); } else if (pid == (pid_t)-1) { err = ff_log(FC_WARN, errno, "fork() failed"); } else { /* parent */ err = -ECHILD; // assume failure unless proved successful... int status = 0; if (waitpid(pid, & status, 0/*options*/) != pid) { err = ff_log(FC_WARN, errno, "error in waitpid(), assuming command '%s' failed", path); if (err == 0) err = -ECHILD; } else if (WIFEXITED(status)) { status = WEXITSTATUS(status); if (status == 0) err = 0; // proved successful! else ff_log(FC_DEBUG, 0, "command '%s' exited with non-zero exit status %d", path, status); } else if (WIFSIGNALED(status)) ff_log(FC_DEBUG, 0, "command '%s' died with signal %d", path, (int)WTERMSIG(status)); else ff_log(FC_WARN, 0, "waitpid() returned unknown status %d, assuming command '%s' failed", status, path); } return err; } FT_IO_NAMESPACE_END fstransform-0.9.4/fsmove/src/io/util_posix.hh000066400000000000000000000026231345021500300213010ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/util_posix.hh * * Created on: Mar 27, 2012 * Author: max */ #ifndef FSMOVE_IO_POSIX_UTIL_HH #define FSMOVE_IO_POSIX_UTIL_HH #include "../types.hh" FT_IO_NAMESPACE_BEGIN /** * spawn a system command, wait for it to complete and return its exit status. * argv[0] is conventionally the program name. * argv[1...] are program arguments and must be terminated with a NULL pointer. */ int ff_posix_exec_silent(const char * path, const char * const argv[]); FT_IO_NAMESPACE_END #endif /* FSREMAP_IO_POSIX_UTIL_HH */ fstransform-0.9.4/fsmove/src/log.cc000077700000000000000000000000001345021500300231742../../fsremap/src/log.ccustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/log.hh000077700000000000000000000000001345021500300232202../../fsremap/src/log.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/main.cc000066400000000000000000000027371345021500300174130ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * main.cc * Created on: Aug 18, 2011 * Author: max */ #include "first.hh" #undef FM_TEST_ROPE #undef FM_TEST_ZSTRING #if defined(FM_TEST_ROPE) # include "rope/rope_test.hh" // rope self-test #define FM_MAIN(argc, argv) FT_NS rope_test(argc, argv) #elif defined(FM_TEST_ZSTRING) # include "zstring.hh" // zstring self-test #define FM_MAIN(argc, argv) FT_NS ztest() #else # include "move.hh" // actual fsmove program # define FM_MAIN(argc, argv) FT_NS fm_move::main(argc, argv) #endif // defined(FT_TEST_*) int main(int argc, char ** argv) { return FM_MAIN(argc, argv); } fstransform-0.9.4/fsmove/src/misc.cc000077700000000000000000000000001345021500300235202../../fsremap/src/misc.ccustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/misc.hh000077700000000000000000000000001345021500300235442../../fsremap/src/misc.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/move.cc000066400000000000000000000406201345021500300174260ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * move.cc * * Created on: Aug 18, 2011 * Author: max */ #include "first.hh" #include "move.hh" #include "io/io.hh" // for fm_io #include "io/io_posix.hh" // for fm_io_posix #include "io/io_prealloc.hh" // for fm_io_prealloc #if defined(FT_HAVE_STRING_H) # include // for atoi() #elif defined(FT_HAVE_CSTRING) # include // for atoi() #endif #if defined(FT_HAVE_STRING_H) # include // for strcmp() #elif defined(FT_HAVE_CSTRING) # include // for strcmp() #endif #include // for std::vector FT_NAMESPACE_BEGIN enum { FC_ARGS_COUNT = FT_IO_NS fm_io::FC_ARGS_COUNT }; // static char const* const* label = FT_IO_NS fm_io::label; static char const* const* LABEL = FT_IO_NS fm_io::LABEL; /** default constructor */ fm_move::fm_move() : this_io(0), quit_immediately(false) { } /** destructor. calls quit() */ fm_move::~fm_move() { quit(); } /** * checks that I/O is open. * if success, stores a reference to I/O object. */ int fm_move::init(FT_IO_NS fm_io & io) { int err = 0; if (this_io->is_open()) this_io = & io; else err = ENOTCONN; // I/O is not open ! return err; } /** performs cleanup. called by destructor, you can also call it explicitly after (or instead of) run() */ void fm_move::quit() { if (this_io != NULL) { if (this_io->is_open()) this_io->close(); this_io = NULL; } } bool fm_move::is_initialized() const { return this_io != NULL && this_io->is_open(); } /** return EISCONN if remapper is initialized, else call quit_io() and return 0 */ int fm_move::check_is_closed() { int err = 0; if (is_initialized()) { ff_log(FC_ERROR, 0, "error: I/O subsystem already started"); /* error is already reported, flip sign */ err = -EISCONN; } else // quit() to make sure we are not left in a half-initialized status // (this_io != NULL && !this_io->is_open()) quit(); return err; } /** return 0 if remapper is initialized, else ENOTCONN */ int fm_move::check_is_open() { int err = 0; if (!is_initialized()) { ff_log(FC_ERROR, 0, "error: I/O subsystem not started"); // quit() to make sure we are not left in a half-initialized status // (this_io != NULL && !this_io->is_open()) quit(); /* error is already reported, flip sign */ err = -ENOTCONN; } return err; } /** * high-level do-everything method. calls in sequence init(), run() and cleanup(). * return 0 if success, else error. */ int fm_move::main(int argc, char ** argv) { #ifdef ZTEST ztest(); ztest_ptr(); #endif fm_move mover; int err = mover.init(argc, argv); if (err == 0 && !mover.quit_immediately) err = mover.run(); /* * note 1.2.2) fsmove::main() must check for unreported errors * and log them them with message "failed with unreported error" */ if (!ff_log_is_reported(err)) err = ff_log(FC_ERROR, err, "failed with unreported error"); return err; } /** print command-line usage to stdout and return 0 */ int fm_move::usage(const char * program_name) { quit_immediately = true; ff_log(FC_NOTICE, 0, "Usage: %s [OPTION]... %s %s [--exclude FILE...]", program_name, LABEL[0], LABEL[1]); ff_log(FC_NOTICE, 0, "Recursively move files and folders from %s to %s,", LABEL[0], LABEL[1]); ff_log(FC_NOTICE, 0, "even if %s and %s are almost full or share their free space", LABEL[0], LABEL[1]); ff_log(FC_NOTICE, 0, "(for example if %s is a file system inside a loop-file _inside_ %s)\n", LABEL[1], LABEL[0]); return ff_log(FC_NOTICE, 0, "Mandatory arguments to long options are mandatory for short options too.\n" " -- end of options. treat subsequent parameters as arguments\n" " even if they start with '-'\n" " -e, --exclude FILE... skip these files, i.e. do not move them.\n" " must be last argument\n" " -f, --force-run run even if some safety checks fail\n" " --io=posix use POSIX I/O and move files (default)\n" #ifdef FT_HAVE_FM_IO_IO_PREALLOC " --io=prealloc use POSIX I/O and preallocate files (do NOT move them)\n" #endif " --inode-cache-mem use in-memory inode cache (default)\n" " --inode-cache=DIR create and use directory DIR for inode cache\n" " --log-color=MODE set messages color. MODE is one of:" " auto (default), none, ansi\n" " --log-format=FMT set messages format. FMT is one of:\n" " msg (default), level_msg, time_level_msg,\n" " time_level_function_msg\n" " -n, --no-action, --simulate-run\n" " do not actually move any file or directory\n" " -q, --quiet be quiet\n" " -qq be very quiet, only print warnings or errors\n" " -v, --verbose be verbose, print what is being done\n" " -vv be very verbose, print a lot of detailed output\n" " -vvv be incredibly verbose (warning: prints LOTS of output)\n" " --help display this help and exit\n" " --version output version information and exit\n"); } /** output version information and return 0 */ int fm_move::version() { quit_immediately = true; return ff_log(FC_NOTICE, 0, "fsmove (fstransform utilities) " FT_VERSION "\n" "Copyright (C) 2011-2017 Massimiliano Ghilardi\n" "\n" "License GPLv3+: GNU GPL version 3 or later .\n" "This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law.\n"); } int fm_move::invalid_cmdline(const char * program_name, int err, const char * fmt, ...) { va_list args; va_start(args, fmt); err = ff_vlog(FC_ERROR, err, fmt, args); va_end(args); ff_log(FC_NOTICE, 0, "Try `%s --help' for more information", program_name); /* mark error as reported */ return err ? err : -EINVAL; } /** * parse command line and initialize all subsystems (job, I/O, log...) * return 0 if success, else error. * * implementation: parse command line, fill a fm_args and call init(const fm_args &) */ int fm_move::init(int argc, char const* const* argv) { fm_args args; int err; fm_io_kind io_kind; ft_log_fmt format = FC_FMT_MSG; ft_log_level level = FC_INFO, new_level; ft_log_color color = FC_COL_AUTO; bool format_set = false; do { if ((err = check_is_closed()) != 0) break; if (argc == 0) { err = invalid_cmdline("fsmove", 0, "missing arguments: %s %s", LABEL[0], LABEL[1]); break; } const char * arg, * program_name = argv[0]; ft_size io_args_n = 0; bool allow_opts = true; // skip program_name while (err == 0 && --argc) { arg = * ++argv; /* -e is allowed even after '--', but must be last argument */ if (io_args_n == FC_ARGS_COUNT && argc > 0 && arg[0] == '-' && (!strcmp(arg, "-e") || !strcmp(arg, "--exclude")) ) { args.exclude_list = argv + 1; // -e uses all remaining arguments, so stop processing them break; } if (allow_opts && arg[0] == '-') { /* -- end of options*/ if (!strcmp(arg, "--")) allow_opts = false; /* -q, --quiet decrease verbosity by one */ /* -qq decrease verbosity by two */ /* -v, --verbose increase verbosity by one */ /* -vv increase verbosity by two */ /* -vvv increase verbosity by three */ else if ((new_level = FC_WARN, !strcmp(arg, "-qq")) || (new_level = FC_NOTICE, !strcmp(arg, "-q") || !strcmp(arg, "--quiet")) || (new_level = FC_DEBUG, !strcmp(arg, "-v") || !strcmp(arg, "--verbose")) || (new_level = FC_TRACE, !strcmp(arg, "-vv")) || (new_level = FC_DUMP, !strcmp(arg, "-vvv"))) { if (level == FC_INFO) level = new_level; else { err = invalid_cmdline(program_name, 0, "options -q, -qq, -v, -vv, -vvv, --quiet, --verbose are mutually exclusive"); break; } } else if (!strncmp(arg, "--log-color=", 12)) { /* --color=(auto|none|ansi) */ arg += 12; if (!strcmp(arg, "ansi")) color = FC_COL_ANSI; else if (!strcmp(arg, "none")) color = FC_COL_NONE; else color = FC_COL_AUTO; } else if (!strncmp(arg, "--log-format=", 13)) { /* --color=(auto|none|ansi) */ arg += 13; if (!strcmp(arg, "level_msg")) format = FC_FMT_LEVEL_MSG; else if (!strcmp(arg, "time_level_msg")) format = FC_FMT_DATETIME_LEVEL_MSG; else if (!strcmp(arg, "time_level_function_msg")) format = FC_FMT_DATETIME_LEVEL_CALLER_MSG; else format = FC_FMT_MSG; format_set = true; } else if (!strncmp(arg, "--x-log-", 8)) { /* --x-log-FILE=LEVEL */ arg += 8; const char * equal = strchr(arg, '='); ft_mstring logger_name(arg, equal ? equal - arg : strlen(arg)); ft_log_level logger_level = equal ? (ft_log_level) atoi(equal+1) : FC_INFO; ft_log::get_logger(logger_name).set_level(logger_level); } /* -f force run: degrade failed sanity checks from ERRORS (which stop execution) to WARNINGS (which let execution continue) */ else if (!strcmp(arg, "-f") || !strcmp(arg, "--force-run")) { args.force_run = true; } /* -n simulate run: do not read or write device blocks */ else if (!strcmp(arg, "-n") || !strcmp(arg, "--no-action") || !strcmp(arg, "--simulate-run")) { args.simulate_run = true; } /* --io=posix */ else if ((io_kind = FC_IO_POSIX, !strcmp(arg, "--io=posix")) #ifdef FT_HAVE_FM_IO_IO_PREALLOC || (io_kind = FC_IO_PREALLOC, !strcmp(arg, "--io=prealloc")) #endif ) { if (args.io_kind == FC_IO_AUTODETECT) args.io_kind = io_kind; else { #ifdef FT_HAVE_FM_IO_IO_PREALLOC err = invalid_cmdline(program_name, 0, "options --io=posix and --io=prealloc are mutually exclusive"); #else err = invalid_cmdline(program_name, 0, "option --io=posix can be specified only once"); #endif } } else if (!strcmp(arg, "--inode-cache-mem")) { args.inode_cache_path = NULL; } else if (!strncmp(arg, "--inode-cache=", 14)) { // do not allow empty dir name if (arg[14] != '\0') args.inode_cache_path = arg + 14; } else if (!strcmp(arg, "--help")) { return usage(args.program_name); } else if (!strcmp(arg, "--version")) { return version(); } else { err = invalid_cmdline(program_name, 0, "unknown option: '%s'", arg); break; } continue; } /** found an argument */ if (io_args_n < FC_ARGS_COUNT) args.io_args[io_args_n++] = arg; else err = invalid_cmdline(program_name, 0, "too many arguments"); } if (err != 0) break; /* if autodetect, use POSIX I/O */ if (args.io_kind == FC_IO_AUTODETECT) args.io_kind = FC_IO_POSIX; if (args.io_kind == FC_IO_POSIX || args.io_kind == FC_IO_PREALLOC) { if (io_args_n == 0) { err = invalid_cmdline(program_name, 0, "missing arguments: %s %s", LABEL[0], LABEL[1]); break; } else if (io_args_n == 1) { err = invalid_cmdline(program_name, 0, "missing argument: %s", LABEL[1]); break; } const char * source_root = args.io_args[FT_IO_NS fm_io::FC_SOURCE_ROOT]; if (args.inode_cache_path != NULL && source_root != NULL && (args.inode_cache_path[0] == '/') != (source_root[0] == '/')) { err = invalid_cmdline(program_name, 0, "relative/absolute path mismatch between source directory `%s'\n" "\tand inode-cache directory `%s':\n" "\tthey must be either both absolute, i.e. starting with `/',\n" "\tor both relative, i.e. NOT starting with `/'", source_root, args.inode_cache_path); break; } } } while (0); if (err == 0) { ft_log::get_root_logger().set_level(level); /* note 1.4.1) -v sets format FC_FMT_LEVEL_MSG */ /* note 1.4.2) -vv sets format FC_FMT_DATETIME_LEVEL_MSG */ if (!format_set) format = level < FC_DEBUG ? FC_FMT_DATETIME_LEVEL_MSG : level == FC_DEBUG ? FC_FMT_LEVEL_MSG : FC_FMT_MSG; // no dot alter appenders min_level ft_log_appender::reconfigure_all(format, FC_LEVEL_NOT_SET, color); err = init(args); } return err; } /** * initialize all subsystems (job, I/O, log...) using specified arguments * return 0 if success, else error. */ int fm_move::init(const fm_args & args) { FT_IO_NS fm_io * io = NULL; int err = 0; switch (args.io_kind) { case FC_IO_POSIX: if ((err = check_is_closed()) != 0) break; io = new FT_IO_NS fm_io_posix(); break; #ifdef FT_HAVE_FM_IO_IO_PREALLOC case FC_IO_PREALLOC: if ((err = check_is_closed()) != 0) break; io = new FT_IO_NS fm_io_prealloc(); break; #endif default: ff_log(FC_ERROR, 0, "tried to initialize unknown I/O '%d': not POSIX" #ifdef FT_HAVE_FM_IO_IO_PREALLOC ", not PREALLOC" #endif , (int) args.io_kind); err = -ENOSYS; break; } if (io != NULL) { if ((err = io->open(args)) == 0) this_io = io; else delete io; } return err; } /** * main recursive move algorithm. * calls move() */ int fm_move::run() { return move(); } /** core of recursive move algorithm, actually moves the whole source tree into target */ int fm_move::move() { return this_io->move(); } FT_NAMESPACE_END fstransform-0.9.4/fsmove/src/move.hh000066400000000000000000000066171345021500300174500ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * move.hh * * Created on: Aug 18, 2011 * Author: max */ #ifndef FSMOVE_MOVE_HH #define FSMOVE_MOVE_HH #include "args.hh" // for fm_args #include "fwd.hh" // for fm_io forward declaration #include "log.hh" // for FC_TRACE FT_NAMESPACE_BEGIN /** * class doing the core of recursive move work. */ class fm_move { private: FT_IO_NS fm_io * this_io; /** true if usage() or version() was called. */ bool quit_immediately; /** cannot call copy constructor */ fm_move(const fm_move &); /** cannot call assignment operator */ const fm_move & operator=(const fm_move &); /** display command-line usage to stdout and return 0 */ int usage(const char * program_name); /** output version information and return 0 */ int version(); static int invalid_cmdline(const char * program_name, int err, const char * fmt, ...); /** return EISCONN if remapper is initialized, else call quit_io() and return 0 */ int check_is_closed(); /** return 0 if remapper is initialized, else call quit_io() and return ENOTCONN */ int check_is_open(); /** * checks that I/O is open. * if success, stores a reference to I/O object. */ int init(FT_IO_NS fm_io & io); /** core of recursive move algorithm, actually moves the whole source tree into target */ int move(); /** show progress status and E.T.A. */ void show_progress(); public: /** default constructor */ fm_move(); /** destructor. calls quit() */ ~fm_move(); /** * high-level do-everything method. calls in sequence init(), run() and cleanup(). * return 0 if success, else error. */ static int main(int argc, char ** argv); bool is_initialized() const; /** * parse command line and initialize all subsystems (job, I/O, log...) * return 0 if success, else error. * * implementation: parse command line, fill a fr_args and call init(const fr_args &) */ int init(int argc, char const* const* argv); /** * initialize all subsystems (job, I/O, log...) using specified arguments * return 0 if success, else error. */ int init(const fm_args & args); /** * main recursive move algorithm. * calls in sequence analyze() and move() */ int run(); /** * performs cleanup. called by destructor, you can also call it explicitly after (or instead of) run(). * closes configured I/O and delete it */ void quit(); }; FT_NAMESPACE_END #endif /* FSMOVE_MOVE_HH */ fstransform-0.9.4/fsmove/src/mstring.cc000077700000000000000000000000001345021500300250002../../fsremap/src/mstring.ccustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/mstring.hh000077700000000000000000000000001345021500300250242../../fsremap/src/mstring.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/rope/000077500000000000000000000000001345021500300171145ustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/rope/rope.cc000066400000000000000000000060771345021500300204020ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * rope.cc * * Created on: Mar 3, 2018 * Author: max */ #include "../first.hh" #include // for std::invalid_argument #include "rope.hh" // for ft_rope #include "rope_impl.hh" // for ft_rope_impl FT_NAMESPACE_BEGIN /** copy constructor. */ ft_rope::ft_rope(const ft_rope & other) : p(NULL) { other.validate(); if (other.p != NULL) { other.p->ref(); p = other.p; } } /** constructor from ft_string */ ft_rope::ft_rope(const ft_string & other) : p(NULL) { if (other.size() != 0) p = ft_rope_impl::make(NULL, other.c_str(), other.size()); } /** constructor with prefix and suffix. makes a private copy of 'suffix' */ ft_rope::ft_rope(const ft_rope * prefix, const char * suffix, ft_size suffix_length) : p(NULL) { if (prefix) prefix->validate(); ft_rope_impl * prefix_p = prefix ? prefix->p : NULL; if (prefix_p != NULL || suffix_length != 0) p = ft_rope_impl::make(prefix_p, suffix, suffix_length); } /** assignment operator */ const ft_rope & ft_rope::operator=(const ft_rope & other) { validate(); other.validate(); if (this->p != other.p) { if (p != NULL) { p->unref(); p = NULL; } if ((other.p != NULL)) { other.p->ref(); p = other.p; } } return *this; } /* destructor */ ft_rope::~ft_rope() { validate(); if (p != NULL) { p->unref(); p = NULL; } } bool ft_rope::empty() const { return p == NULL || p->empty(); } /* validate ft_rope_impl pointer */ void ft_rope::validate() const { if (p == NULL) return; ft_size n = (ft_size)p; if ((n & 7) || n <= 0xffff) throw std::invalid_argument("invalid ft_rope_impl pointer"); } /** convert to ft_string */ void ft_rope::to_string(ft_string & append_dst) const { validate(); if (p != NULL) p->to_string(append_dst); } /** compare against char[] */ bool ft_rope::equals(const char other[], ft_size other_len) const { validate(); if (p == NULL) return other_len == 0; return p->equals(other, other_len); } /** return this hash */ ft_size ft_rope::hash() const { validate(); return p ? p->hash() : ft_rope_impl::hash(NULL, 0); } /** return other's hash */ ft_size ft_rope::hash(const char other[], ft_size other_len) { return ft_rope_impl::hash(other, other_len); } FT_NAMESPACE_END fstransform-0.9.4/fsmove/src/rope/rope.hh000066400000000000000000000055431345021500300204110ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * rope.hh * * Created on: Mar 3, 2018 * Author: max */ #ifndef FSTRANSFORM_ROPE_HH #define FSTRANSFORM_ROPE_HH #include "../types.hh" // for ft_string, ft_size FT_NAMESPACE_BEGIN class ft_rope_impl; // ----------------------------------------------------------------------------- /** * short immutable string, with a prefix shared with other rope:s */ class ft_rope { private: ft_rope_impl * p; public: /** default constructor. */ FT_INLINE ft_rope() : p(NULL) { } /** copy constructor. */ ft_rope(const ft_rope & other); /** constructor from ft_string */ explicit ft_rope(const ft_string & other); /** constructor with prefix and suffix. makes a private copy of 'suffix' */ ft_rope(const ft_rope * prefix, const char * suffix, ft_size suffix_length); /** assignment operator */ const ft_rope & operator=(const ft_rope & other); /** destructor */ ~ft_rope(); /** * identity comparison: returns true ONLY if pointing to the same ft_rope_impl. * enough for the comparison against empty ft_rope() made by ft_cache_mem. * does NOT compare the char[] array! */ FT_INLINE bool operator==(const ft_rope & other) const { return p == other.p; } FT_INLINE bool operator!=(const ft_rope & other) const { return p != other.p; } bool empty() const; /* validate ft_rope_impl pointer */ void validate() const; /** convert to ft_string */ void to_string(ft_string & append_dst) const; /** compare against char[] */ bool equals(const char other[], ft_size other_len) const; /** compare against ft_string */ FT_INLINE bool equals(const ft_string & other) const { return equals(other.c_str(), other.size()); } /** return this hash */ ft_size hash() const; /** return other's hash */ static ft_size hash(const char other[], ft_size other_len); /** return other's hash */ static FT_INLINE ft_size hash(const ft_string & other) { return hash(other.c_str(), other.size()); } }; FT_NAMESPACE_END #endif /* FSTRANSFORM_ROPE_HH */ fstransform-0.9.4/fsmove/src/rope/rope_impl.cc000066400000000000000000000142161345021500300214150ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * rope_impl.cc * * Created on: Mar 3, 2018 * Author: max */ #include "../first.hh" #include // for std::bad_alloc #include // for std::length_error #if defined(FT_HAVE_STDLIB_H) # include // for malloc(), free() #elif defined(FT_HAVE_CSTDLIB) # include // for malloc(), free() #endif #if defined(FT_HAVE_STRING_H) # include // for memcmp(), memcpy() #elif defined(FT_HAVE_CSTRING) # include // for memcmp(), memcpy() #endif #include "../log.hh" #include "rope_impl.hh" FT_NAMESPACE_BEGIN static bool unaligned_malloc_warn_once = true; // ----------------------------------------------------------------------------- /** create an empty rope */ ft_rope_impl * ft_rope_impl::make() { return make(NULL, NULL, 0); } /** create a rope with given prefix and suffix. makes a private copy of 'suffix' */ ft_rope_impl * ft_rope_impl::make(ft_rope_impl * prefix, const char * suffix, ft_size suffix_length) { char * bytes = reinterpret_cast(malloc(sizeof(ft_rope_impl) + suffix_length)); if (bytes == NULL) throw std::bad_alloc(); if (((ft_size)bytes % PREFIX_SCALE) != 0 && unaligned_malloc_warn_once) { unaligned_malloc_warn_once = false; ff_log(FC_WARN, 0, "malloc() returned unaligned pointer %p, ft_rope will not be memory-saving", bytes); } if (!prefix || ((ft_size)bytes % PREFIX_SCALE) == ((ft_size)prefix % PREFIX_SCALE)) { // check whether prefix_delta can point to prefix ft_i32 delta = prefix ? (ft_i32)(((ft_size)prefix - (ft_size)bytes) / PREFIX_SCALE) : 0; if (!prefix || (ft_size)bytes + (ft_size)delta * PREFIX_SCALE == (ft_size)prefix) { if (suffix_length != (ft_u32)suffix_length) throw std::length_error("string too long for ft_rope"); ft_rope_impl * ths = reinterpret_cast(bytes); new (ths) ft_rope_impl(); // placement new if ((ths->suffix_len = suffix_length) != 0) memcpy(ths->suffix(), suffix, suffix_length); ths->prefix_delta = delta; if (prefix != NULL) prefix->ref(); return ths; } } // cannot point to prefix... copy it free(bytes); ft_size prefix_len = prefix->len(); if (prefix_len + suffix_length != (ft_u32)(prefix_len + suffix_length)) throw std::length_error("string too long for ft_rope"); bytes = reinterpret_cast(malloc(sizeof(ft_rope_impl) + prefix_len + suffix_length)); if (bytes == NULL) throw std::bad_alloc(); ft_rope_impl * ths = reinterpret_cast(bytes); new (ths) ft_rope_impl(); // placement new char * dst = ths->suffix() + prefix_len; if ((ths->suffix_len = suffix_length) != 0) memcpy(dst, suffix, suffix_length); do { if ((prefix_len = prefix->suffix_len) != 0) memcpy(dst -= prefix_len, prefix->suffix(), prefix_len); prefix = prefix->prefix(); } while (prefix); return ths; } /** destructor. private use only. call unref() instead */ ft_rope_impl::~ft_rope_impl() { if (prefix_delta != 0) { prefix()->unref(); prefix_delta = 0; } suffix_len = 0; } /** increment reference count */ void ft_rope_impl::ref() { switch (refcount) { case (ft_u32)-1: break; case (ft_u32)-2: ff_log(FC_DEBUG, 0, "ft_rope %p refcount reached 2^32-1", this); // FALLTHROUGH default: refcount++; break; } } /** decrement reference count */ void ft_rope_impl::unref() { if (refcount == (ft_u32)-1 || refcount-- != 0) return; this->~ft_rope_impl(); free(this); } bool ft_rope_impl::empty() const { const ft_rope_impl * p = this; do { if (p->suffix_len != 0) return false; } while ((p = p->prefix()) != NULL); return true; } ft_size ft_rope_impl::len() const { const ft_rope_impl * p = this; ft_size n = 0; do { n += p->suffix_len; } while ((p = p->prefix()) != NULL); return n; } /** convert to ft_string */ void ft_rope_impl::to_string(ft_string & append_dst) const { ft_size ths_len = len(); if (ths_len == 0) return; ft_size dst_len = append_dst.size(); append_dst.resize(dst_len + ths_len); char * end_dst = &append_dst[0] + dst_len + ths_len; const ft_rope_impl * p = this; do { if (p->suffix_len != 0) memcpy(end_dst -= p->suffix_len, p->suffix(), p->suffix_len); } while ((p = p->prefix()) != NULL); } /** compare against char[] */ bool ft_rope_impl::equals(const char other[], ft_size other_len) const { ft_size ths_len = len(); if (ths_len != other_len) return false; other += other_len; const ft_rope_impl * p = this; do { if (p->suffix_len != 0) if (memcmp(other -= p->suffix_len, p->suffix(), p->suffix_len)) return false; } while ((p = p->prefix()) != NULL); return true; } /** return this hash */ ft_size ft_rope_impl::hash() const { const ft_rope_impl * p = this; ft_size h = 0; do { const char * str = p->suffix(), * end = str + p->suffix_len; while (str != end) h = *--end + (h << 16) + (h << 6) - h; } while ((p = p->prefix()) != NULL); // ff_log(FC_INFO, 0, "hash = 0x%016llx of {%p, \"%.*s\"}", (unsigned long long)h, prefix(), (int)suffix_len, suffix()); return h; } /** return other's hash */ ft_size ft_rope_impl::hash(const char other[], ft_size other_len) { const char * end = other + other_len; ft_size h = 0; while (other != end) h = *--end + (h << 16) + (h << 6) - h; // ff_log(FC_INFO, 0, "hash = 0x%016llx of \"%.*s\"", (unsigned long long)h, (int)other_len, other); return h; } FT_NAMESPACE_END fstransform-0.9.4/fsmove/src/rope/rope_impl.hh000066400000000000000000000062051345021500300214260ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * rope_impl.hh * * Created on: Mar 3, 2018 * Author: max */ #ifndef FSTRANSFORM_ROPE_IMPL_HH #define FSTRANSFORM_ROPE_IMPL_HH #include "../types.hh" // for ft_string, ft_size FT_NAMESPACE_BEGIN /** * short immutable string, with a prefix shared with other rope:s */ class ft_rope_impl { private: enum { PREFIX_SCALE = sizeof(void *) }; ft_i32 prefix_delta; ft_u32 refcount, suffix_len; /** default constructor. private use only, call make() instead */ FT_INLINE ft_rope_impl() : prefix_delta(0), refcount(0), suffix_len(0) { } /** copy constructor. forbidden. call make() instead */ ft_rope_impl(const ft_rope_impl & other); /** assignment operator. forbidden */ const ft_rope_impl & operator=(const ft_rope_impl & other); /** * constructor. private use only. call make() instead. * makes a copy of 'suffix' */ FT_INLINE ft_rope_impl(ft_rope_impl * prefix_ptr, ft_size suffix_length); /** destructor. private use only. call unref() instead */ ~ft_rope_impl(); FT_INLINE char * suffix() { return reinterpret_cast(this) + sizeof(ft_rope_impl); } FT_INLINE const char * suffix() const { return reinterpret_cast(this) + sizeof(ft_rope_impl); } FT_INLINE ft_rope_impl * prefix() const { if (!prefix_delta) return NULL; ft_size self = (ft_size)(this); return reinterpret_cast(self + (ft_size)prefix_delta * PREFIX_SCALE); } FT_INLINE ft_size prefix_len() const { ft_rope_impl * ptr = prefix(); return ptr ? ptr->len() : 0; } public: /** create an empty rope */ static ft_rope_impl * make(); /** create a rope with given prefix and suffix. makes a private copy of 'suffix' */ static ft_rope_impl * make(ft_rope_impl * prefix, const char * suffix, ft_size suffix_length); /** increment reference count */ void ref(); /** decrement reference count */ void unref(); bool empty() const; ft_size len() const; /** convert to ft_string */ void to_string(ft_string & append_dst) const; /** compare against char[] */ bool equals(const char other[], ft_size other_len) const; /** return this hash */ ft_size hash() const; /** return other's hash */ static ft_size hash(const char other[], ft_size other_len); }; FT_NAMESPACE_END #endif /* FSTRANSFORM_ROPE_IMPL_HH */ fstransform-0.9.4/fsmove/src/rope/rope_list.cc000066400000000000000000000042771345021500300214350ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * rope_list.cc * * Created on: Mar 3, 2018 * Author: max */ #include "../first.hh" #include // for std::out_of_range #include "rope_list.hh" // for ft_rope_list FT_NAMESPACE_BEGIN /** copy constructor. */ ft_rope_list::ft_rope_list(const ft_rope_list & other) : head(NULL) { init(other.head); } /** assignment operator */ const ft_rope_list & ft_rope_list::operator=(const ft_rope_list & other) { if (head != other.head) { clear(); init(other.head); } return *this; } void ft_rope_list::clear() { ft_rope_node * next; while (head != NULL) { next = head->next; delete head; head = next; } } void ft_rope_list::init(const ft_rope_node * list) { head = NULL; ft_rope_node ** dst = &head; while (list != NULL) { *dst = new ft_rope_node(list->e); dst = & (*dst)->next; list = list->next; } } ft_rope & ft_rope_list::front() { ft_rope_node * node = head; if (node == NULL) throw std::out_of_range("ft_rope_list::front(): list is empty"); return node->e; } void ft_rope_list::pop_front() { ft_rope_node * node = head; if (node == NULL) throw std::out_of_range("ft_rope_list::pop_front(): list is empty"); head = node->next; delete node; } void ft_rope_list::push_front(const ft_rope & e) { ft_rope_node * node = new ft_rope_node(e, head); head = node; } FT_NAMESPACE_END fstransform-0.9.4/fsmove/src/rope/rope_list.hh000066400000000000000000000074361345021500300214470ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * rope_list.hh * * Created on: Mar 4, 2018 * Author: max */ #ifndef FSTRANSFORM_ROPE_LIST_HH #define FSTRANSFORM_ROPE_LIST_HH #include "rope.hh" // for ft_rope FT_NAMESPACE_BEGIN // ----------------------------------------------------------------------------- /** * singly-linked list of ropes */ class ft_rope_list { private: class ft_rope_node { public: ft_rope e; ft_rope_node * next; explicit FT_INLINE ft_rope_node(const ft_rope & el, ft_rope_node * tail = NULL) : e(el), next(tail) { } FT_INLINE ~ft_rope_node() { } }; ft_rope_node * head; void init(const ft_rope_node * list); public: /** default constructor. */ FT_INLINE ft_rope_list() : head(NULL) { } /** copy constructor. */ ft_rope_list(const ft_rope_list & other); /** assignment operator */ const ft_rope_list & operator=(const ft_rope_list & other); /** destructor */ FT_INLINE ~ft_rope_list() { clear(); } FT_INLINE bool empty() const { return head == NULL; } void clear(); ft_rope & front(); void pop_front(); void push_front(const ft_rope & e); FT_INLINE const ft_rope & front() const { return const_cast(this)->front(); } class iterator { private: friend class ft_rope_list; ft_rope_node * node; explicit FT_INLINE iterator(ft_rope_node * list) : node(list) { } public: /** default constructor. */ FT_INLINE iterator() : node(NULL) { } /** dereference. */ FT_INLINE ft_rope & operator*() { return node->e; } /** operator-> */ FT_INLINE ft_rope * operator->() { return & node->e; } /** pre-increment */ FT_INLINE iterator & operator++() { node = node->next; return *this; } /** comparison. */ FT_INLINE bool operator==(const iterator & other) const { return node == other.node; } FT_INLINE bool operator!=(const iterator & other) const { return node != other.node; } }; class const_iterator { private: friend class ft_rope_list; const ft_rope_node * node; explicit FT_INLINE const_iterator(const ft_rope_node * list) : node(list) { } public: /** default constructor. */ FT_INLINE const_iterator() : node(NULL) { } /** dereference. */ FT_INLINE const ft_rope & operator*() { return node->e; } /** operator-> */ FT_INLINE const ft_rope * operator->() { return & node->e; } /** pre-increment */ FT_INLINE const_iterator & operator++() { node = node->next; return *this; } /** comparison. */ FT_INLINE bool operator==(const const_iterator & other) const { return node == other.node; } FT_INLINE bool operator!=(const const_iterator & other) const { return node != other.node; } }; iterator begin() { return iterator(head); } const_iterator begin() const { return const_iterator(head); } iterator end() { return iterator(); } const_iterator end() const { return const_iterator(); } }; FT_NAMESPACE_END #endif /* FSTRANSFORM_ROPE_LIST_HH */ fstransform-0.9.4/fsmove/src/rope/rope_pool.cc000066400000000000000000000066671345021500300214400ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * rope_pool.cc * * Created on: Mar 3, 2018 * Author: max */ #include "../first.hh" #include "rope_impl.hh" #include "rope_pool.hh" FT_NAMESPACE_BEGIN /** default constructor. */ ft_rope_pool::ft_rope_pool() : count(0), table() { } /** copy constructor. */ ft_rope_pool::ft_rope_pool(const ft_rope_pool & other) : count(other.count), table(other.table) { } /** assignment operator. */ const ft_rope_pool & ft_rope_pool::operator=(const ft_rope_pool & other) { if (this != & other) { count = other.count; table = other.table; } return *this; } /** destructor. */ ft_rope_pool::~ft_rope_pool() { } void ft_rope_pool::rehash(ft_size new_len) { // assert((new_len & new_lenn-1)) == 0); // must be power-of-two ft_table tmp(new_len); tmp.swap(table); ft_bucket::const_iterator iter, end; for (ft_size i = 0, n = tmp.size(); i < n; i++) { const ft_bucket & bucket = tmp[i]; iter = bucket.begin(); end = bucket.end(); for (; iter != end; ++iter) { const ft_rope & r = *iter; ft_size index = r.hash() & (new_len - 1); table[index].push_front(r); } } } // returned pointer is valid only while pool is not modified const ft_rope * ft_rope_pool::find(const char s[], ft_size len) const { ft_size n = table.size(); if (n == 0) return NULL; // assert((n & (n-1)) == 0); // must be power-of-two ft_size index = ft_rope::hash(s, len) & (n - 1); const ft_bucket & bucket = table[index]; ft_bucket::const_iterator iter = bucket.begin(), end = bucket.end(); for (; iter != end; ++iter) { const ft_rope & r = *iter; if (r.equals(s, len)) return & r; } return NULL; } ft_rope ft_rope_pool::make(const char s[], ft_size len) { if (len == 0) return ft_rope(); const ft_rope * r = find(s, len); if (r != NULL) return *r; enum { SPLIT_LO = sizeof(ft_rope_impl), SPLIT_HI = SPLIT_LO / 3 }; // rehash() invalidates all pooled (ft_rope *), so prefix cannot be a pointer ft_rope prefix; const char * suffix = s; ft_size suffix_len = len; if (len >= SPLIT_LO + SPLIT_HI) { ft_size split = len - SPLIT_HI; for (; split >= SPLIT_LO; split--) { if (s[split] == '/') { prefix = make(s, ++split); prefix.validate(); suffix += split; suffix_len -= split; break; } } } ft_rope result(& prefix, suffix, suffix_len); if (suffix[suffix_len - 1] == '/') { // only cache directory names ft_size n = table.size(); if (count / 2 >= n) rehash(n = (n ? n * 2 : 64)); ft_size index = ft_rope::hash(s, len) & (n - 1); ft_bucket & bucket = table[index]; bucket.push_front(result); count++; } return result; } FT_NAMESPACE_END fstransform-0.9.4/fsmove/src/rope/rope_pool.hh000066400000000000000000000045171345021500300214420ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * rope_pool.hh * * Created on: Mar 3, 2018 * Author: max */ #ifndef FSTRANSFORM_ROPE_POOL_HH #define FSTRANSFORM_ROPE_POOL_HH #include #include #include "../types.hh" // for ft_string #include "rope.hh" // for ft_rope #include "rope_list.hh" // for ft_rope_list FT_NAMESPACE_BEGIN // ----------------------------------------------------------------------------- /** * pool of ropes. useful to compress large sets of repetitive strings, * in particular for the strings in the inode cache ft_cache */ class ft_rope_pool { private: typedef ft_rope_list ft_bucket; typedef std::vector ft_table; ft_size count; ft_table table; void rehash(ft_size new_len); public: /** default constructor. */ ft_rope_pool(); /** copy constructor. */ ft_rope_pool(const ft_rope_pool & other); /** assignment operator. */ const ft_rope_pool & operator=(const ft_rope_pool & other); /* destructor. */ ~ft_rope_pool(); /** returned pointer is valid only until pool is rehashed. * copy returned ft_rope if you need it further */ const ft_rope * find(const char s[], ft_size len) const; FT_INLINE const ft_rope * find(const ft_string & s) const { return find(s.c_str(), s.size()); } ft_rope make(const char s[], ft_size len); FT_INLINE ft_rope make(const ft_string & s) { return make(s.c_str(), s.size()); } void erase(const ft_string & s); }; FT_NAMESPACE_END #endif /* FSTRANSFORM_ROPE_POOL_HH */ fstransform-0.9.4/fsmove/src/rope/rope_test.cc000066400000000000000000000155741345021500300214430ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * rope.cc * * Created on: Mar 3, 2018 * Author: max */ #include "../first.hh" #if defined(FT_HAVE_STDIO_H) # include // for getchar() #elif defined(FT_HAVE_CSTDIO) # include // for getchar() #endif #if defined(FT_HAVE_STDLIB_H) # include // for free() #elif defined(FT_HAVE_CSTDLIB) # include // for free() #endif #if defined(FT_HAVE_STRING_H) # include // for strcmp(), strdup(), strlen() #elif defined(FT_HAVE_CSTRING) # include // for strcmp(), strdup(), strlen() #endif #ifdef FT_HAVE_FT_UNSORTED_MAP # include "unsorted_map.hh" // for ft_unsorted_map # define ft_map ft_unsorted_map #else # include // for std::map # define ft_map std::map #endif #include "../log.hh" #include "../io/io_posix_dir.hh" #include "../cache/cache_mem.hh" #include "../zstring.hh" #include "rope_test.hh" #include "rope_pool.hh" FT_NAMESPACE_BEGIN static ft_uoff recursive_readdir(ft_unsorted_map & cache, const ft_string & path) { ft_uoff count = 0; io::ft_io_posix_dir dir; if (dir.open(path) != 0) { return count; } io::ft_io_posix_dirent * dirent = NULL; while (dir.next(dirent) == 0 && dirent != NULL) { if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, "..")) continue; ft_string subpath = path; if (subpath[subpath.size() - 1] != '/') subpath += '/'; subpath += dirent->d_name; cache[dirent->d_ino] = subpath; #ifdef DT_DIR if (dirent->d_type == DT_DIR) { count += recursive_readdir(cache, subpath); } #endif } return count; } static ft_uoff recursive_readdir_cstr(ft_unsorted_map & cache, const ft_string & path) { ft_uoff count = 0; io::ft_io_posix_dir dir; if (dir.open(path) != 0) { return count; } io::ft_io_posix_dirent * dirent = NULL; while (dir.next(dirent) == 0 && dirent != NULL) { if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, "..")) continue; ft_string subpath = path; if (subpath[subpath.size() - 1] != '/') subpath += '/'; subpath += dirent->d_name; char * & cstr = cache[dirent->d_ino]; if (cstr) { free(cstr); cstr = NULL; } cstr = strdup(subpath.c_str()); if (!cstr) throw std::bad_alloc(); if (dirent->d_type == DT_DIR) { count += recursive_readdir_cstr(cache, subpath); } } return count; } static ft_uoff recursive_readdir_zstring(ft_unsorted_map & cache, const ft_string & path) { ft_uoff count = 0; io::ft_io_posix_dir dir; if (dir.open(path) != 0) { return count; } io::ft_io_posix_dirent * dirent = NULL; while (dir.next(dirent) == 0 && dirent != NULL) { if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, "..")) continue; ft_string subpath = path; if (subpath[subpath.size() - 1] != '/') subpath += '/'; subpath += dirent->d_name; ft_string & compressed = cache[dirent->d_ino]; compressed.resize(0); z(compressed, subpath); if (dirent->d_type == DT_DIR) { count += recursive_readdir_zstring(cache, subpath); } } return count; } static ft_uoff recursive_readdir_cachemem(ft_cache_mem & cache, const ft_string & path) { ft_uoff count = 0; io::ft_io_posix_dir dir; if (dir.open(path) != 0) { return count; } io::ft_io_posix_dirent * dirent = NULL; while (dir.next(dirent) == 0 && dirent != NULL) { if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, "..")) continue; ft_string subpath = path, tmp; if (subpath[subpath.size() - 1] != '/') subpath += '/'; subpath += dirent->d_name; tmp = subpath; cache.find_or_add(dirent->d_ino, tmp); // modifies tmp! if (dirent->d_type == DT_DIR) { count += recursive_readdir_cachemem(cache, subpath); } } return count; } static ft_uoff recursive_readdir_pool(ft_rope_pool & pool, ft_cache_mem & cache, const ft_string & path) { ft_uoff count = 0; io::ft_io_posix_dir dir; if (dir.open(path) != 0) { return count; } io::ft_io_posix_dirent * dirent = NULL; while (dir.next(dirent) == 0 && dirent != NULL) { if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, "..")) continue; ft_string subpath = path; if (subpath[subpath.size() - 1] != '/') subpath += '/'; subpath += dirent->d_name; ft_rope rope = pool.make(subpath); cache.find_or_add(dirent->d_ino, rope); if (dirent->d_type == DT_DIR) { count += recursive_readdir_pool(pool, cache, subpath); } } return count; } int rope_test(int argc, char ** argv) { ft_string path = "/"; if (argc > 1 && !strcmp(argv[1], "pool")) { ft_rope_pool pool; ft_cache_mem cache; recursive_readdir_pool(pool, cache, path); fputs("recursive_readdir_pool() completed. check RAM usage and press ENTER\n", stdout); fflush(stdout); fgetc(stdin); } else if (argc > 1 && !strcmp(argv[1], "cachemem")) { ft_cache_mem cache; recursive_readdir_cachemem(cache, path); fputs("recursive_readdir_cachemem() completed. check RAM usage and press ENTER\n", stdout); fflush(stdout); fgetc(stdin); } else if (argc > 1 && !strcmp(argv[1], "zstring")) { ft_map cache; recursive_readdir_zstring(cache, path); fputs("recursive_zstring() completed. check RAM usage and press ENTER\n", stdout); fflush(stdout); fgetc(stdin); } else if (argc > 1 && !strcmp(argv[1], "cstr")) { ft_map cache; recursive_readdir_cstr(cache, path); fputs("recursive_readdir_cstr() completed. check RAM usage and press ENTER\n", stdout); fflush(stdout); fgetc(stdin); } else { ft_map cache; recursive_readdir(cache, path); fputs("recursive_readdir() completed. check RAM usage and press ENTER\n", stdout); fflush(stdout); fgetc(stdin); } return 0; } FT_NAMESPACE_END fstransform-0.9.4/fsmove/src/rope/rope_test.hh000066400000000000000000000021731345021500300214440ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * rope_test.hh * * Created on: Mar 3, 2018 * Author: max */ #ifndef FSTRANSFORM_ROPE_TEST_HH #define FSTRANSFORM_ROPE_TEST_HH FT_NAMESPACE_BEGIN int rope_test(int argc, char ** argv); FT_NAMESPACE_END #endif /* FSTRANSFORM_ROPE_TEST_HH */ fstransform-0.9.4/fsmove/src/traits.hh000077700000000000000000000000001345021500300244722../../fsremap/src/traits.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/types.hh000077700000000000000000000000001345021500300241662../../fsremap/src/types.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/unsorted_map.cc000077700000000000000000000000001345021500300270322../../fsremap/src/unsorted_map.ccustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/unsorted_map.hh000077700000000000000000000000001345021500300270562../../fsremap/src/unsorted_map.hhustar00rootroot00000000000000fstransform-0.9.4/fsmove/src/zstring.cc000066400000000000000000000266521345021500300201710ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * zstring.hh * * Created on: Mar 5, 2018 * Author: max */ #include "first.hh" #include // std::sort() #include // std::set #include // std::invalid_argument #include // std::vector #include "zstring.hh" FT_NAMESPACE_BEGIN static const ft_u8 huffman_lengths[256] = { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 7, 11, 11, 11, 11, 11, 11, 11, 12, 11, 11, 11, 11, 6, 5, 3, 6, 6, 7, 7, 7, 7, 7, 8, 7, 8, 11, 11, 11, 11, 11, 11, 11, 9, 9, 8, 8, 8, 9, 9, 10, 8, 11, 11, 9, 8, 10, 10, 8, 11, 10, 8, 8, 10, 10, 9, 10, 11, 11, 11, 11, 11, 11, 6, 11, 4, 6, 5, 5, 4, 6, 6, 6, 4, 8, 7, 5, 5, 5, 4, 6, 10, 5, 5, 5, 6, 7, 7, 6, 8, 9, 11, 12, 12, 12, 11, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }; struct zhuff { ft_u8 sym, len; ft_u16 bits; FT_INLINE void set(ft_u8 symbol, ft_u8 length, ft_u64 bitset) { sym = symbol; len = length; bits = bitset; } }; static FT_INLINE bool operator<(const zhuff & lhs, const zhuff & rhs) { // canonical huffman code ordering. used by zinit() return lhs.len < rhs.len || (lhs.len == rhs.len && lhs.sym < rhs.sym); }; struct unzbyte { // how to decode a single byte ft_u8 nbits[3], sym[3]; }; static ft_u8 code_min_len; static zhuff zvec[256]; enum { UNZBITS = 14 }; // must be >= max(huffman_lengths[]) static unzbyte unztable[1 << UNZBITS]; void zinit() { if (code_min_len != 0) return; code_min_len = 1; zhuff unzvec[256]; for (ft_size i = 0; i < 256; i++) { unzvec[i].set(i, huffman_lengths[i], 0); } std::sort(unzvec, unzvec+256); // rebuild canonical huffman code from lengths ft_u16 bits = unzvec[0].bits = 0; ft_u8 len = unzvec[0].len, newlen; code_min_len = len; for (ft_size i = 1; i < 256; i++) { newlen = unzvec[i].len; bits = (bits+1) << (newlen - len); unzvec[i].bits = bits; len = newlen; } for (ft_size i = 0; i < 256; i++) { zhuff & code = unzvec[i]; zvec[code.sym].set(code.sym, code.len, code.bits); } if (len > (1U << UNZBITS)) throw std::invalid_argument("zstring: decompression table is too small! increase UNZBITS and recompile"); if (UNZBITS > 16) throw std::invalid_argument("zstring: decompression table is too large! decrease UNZBITS and recompile"); ft_u8 ilen, jlen, klen; for (ft_size i = 0; i < 256; i++) { ilen = unzvec[i].len; if (ilen > UNZBITS) break; for (ft_size j = 0; j < 256; j++) { jlen = unzvec[j].len; if (ilen + jlen > UNZBITS) break; for (ft_size k = 0; k < 256; k++) { klen = unzvec[k].len; if (ilen + jlen + klen > UNZBITS) break; ft_u8 free_len = UNZBITS - ilen - jlen - klen; ft_u16 bits = ((ft_u16)unzvec[i].bits << (UNZBITS - ilen)) | ((ft_u16)unzvec[j].bits << (UNZBITS - ilen - jlen)) | ((ft_u16)unzvec[k].bits << free_len); for (ft_size f = 0; f < (1U<= 8) { dst.push_back((ft_u8)(bits >> (len - 8))); len -= 8; } } if (len) { // fill any remainder with ones. 0b111..111 is the longest code: // it will never fit 7 bits or less, so we can just discard // any incomplete last fragment when decompressing bits = (bits << (8-len)) | ((ft_u32)0xff >> len); dst.push_back((ft_u8)bits); } if (!force && dst.size() > src.size()) { // no gain. keep src uncompressed dst = src; } } void unz(ft_string & dst, const ft_string & src) { dst.resize(0); if (src.empty()) return; const char * s = src.c_str(); ft_u32 bits = 0; ft_u8 len = 0; if (s[0] != '\0') { // src is not compressed dst = src; return; } ft_size i = 1, n = src.size(); dst.reserve(n); while (i < n) { do { bits = (bits << 8) | (ft_u8)s[i++]; len += 8; } while (i < n && len <= 24); while (len >= code_min_len) { ft_u16 match_bits = len >= UNZBITS ? (bits >> (len - UNZBITS)) : (bits << (UNZBITS - len)); const unzbyte & entry = unztable[match_bits & ((1< len) break; dst.push_back(entry.sym[0]); len -= nbits; if ((nbits = entry.nbits[1]) && nbits <= len) { dst.push_back(entry.sym[1]); len -= nbits; if ((nbits = entry.nbits[2]) && nbits <= len) { dst.push_back(entry.sym[2]); len -= nbits; } } // actually consume bits bits &= ((ft_u32)0x7fffffffu >> (31 - len)); // (ft_u32)x >> 32 is implementation-defined } } } int ztest() { enum { N = 12 }; ft_string dst, tmp, src[N] = { "/bin/bash", "/sbin/init", "/usr/sbin/apache2", "/usr/lib/bluetooth/obexd", "/usr/lib/python2.7/dist-packages/OpenGL/GLES1/ARM/__init__.py", "/usr/lib/vmware/lib/libglibmm_generate_extra_defs-2.4.so.1/libglibmm_generate_extra_defs-2.4.so.1", "/usr/local/docs/ref/am_conf/byteorder.html", "/sys/devices/pci0000:00/power", "/sys/kernel/mm/transparent_hugepage/khugepaged/alloc_sleep_millisecs", "/media/windows/Users/Default/AppData/Local/Microsoft/Windows/Temporary Internet Files/Content.IE5/87654321/desktop.ini", "/media/windows/Users/Default/AppData/Local/Microsoft/Windows/Temporary Internet Files/Low/Content.IE5/12345678/56K1B4N7B8NY[W95M8MW6948Y69W4MN8BM6WMB98WN8U9GMT8T07DMYTRVVROIWURYNOIMUAOUURREWREWLKMLNBHOIU786RUYFUTFDE64EDCJHGJYURY5ESGFCHDSTSKBOTGO.jpg", "", }; tmp.resize(1024*1024*1024); for (ft_size i = 0, n = tmp.size(); i < n; i++) tmp[i] = (ft_u8)i; src[N-1].swap(tmp); zinit(); for (ft_size i = 0; i < N; i++) { z(tmp, src[i], true); unz(dst, tmp); if (dst != src[i]) throw std::invalid_argument("test failed! mismatch between original and decompressed string"); } return 0; } FT_NAMESPACE_END fstransform-0.9.4/fsmove/src/zstring.hh000066400000000000000000000025031345021500300201700ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * xstring.hh * * Created on: Mar 5, 2018 * Author: max */ #ifndef FSTRANSFORM_ZSTRING_HH #define FSTRANSFORM_ZSTRING_HH #include "types.hh" // for ft_string FT_NAMESPACE_BEGIN int ztest(); void zinit(); /** compress src into dst */ void z(ft_string & dst, const ft_string & src, bool force = false); /** decompress src into dst */ void unz(ft_string & dst, const ft_string & src); FT_NAMESPACE_END #endif /* FSTRANSFORM_ZSTRING_HH */ fstransform-0.9.4/fsremap/000077500000000000000000000000001345021500300155165ustar00rootroot00000000000000fstransform-0.9.4/fsremap/.cproject000066400000000000000000000305001345021500300173260ustar00rootroot00000000000000 fstransform-0.9.4/fsremap/.project000066400000000000000000000014501345021500300171650ustar00rootroot00000000000000 fsremap org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder full,incremental, org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature fstransform-0.9.4/fsremap/.settings/000077500000000000000000000000001345021500300174345ustar00rootroot00000000000000fstransform-0.9.4/fsremap/.settings/language.settings.xml000066400000000000000000000040371345021500300236040ustar00rootroot00000000000000 fstransform-0.9.4/fsremap/build/000077500000000000000000000000001345021500300166155ustar00rootroot00000000000000fstransform-0.9.4/fsremap/build/Makefile.am000066400000000000000000000015161345021500300206540ustar00rootroot00000000000000AUTOMAKE_OPTIONS = subdir-objects sbin_PROGRAMS = fsremap fsremap_SOURCES = \ ../src/arch/mem.cc \ ../src/arch/mem_linux.cc \ ../src/arch/mem_posix.cc \ ../src/args.cc \ ../src/assert.cc \ ../src/dispatch.cc \ ../src/eta.cc \ ../src/io/extent_file.cc \ ../src/io/extent_posix.cc \ ../src/io/io.cc \ ../src/io/io_null.cc \ ../src/io/io_posix.cc \ ../src/io/io_posix_dir.cc \ ../src/io/io_prealloc.cc \ ../src/io/io_self_test.cc \ ../src/io/io_test.cc \ ../src/io/persist.cc \ ../src/io/util_dir.cc \ ../src/io/util_posix.cc \ ../src/job.cc \ ../src/log.cc \ ../src/main.cc \ ../src/map.cc \ ../src/map_stat.cc \ ../src/misc.cc \ ../src/mstring.cc \ ../src/pool.cc \ ../src/remap.cc \ ../src/tmp_zero.cc \ ../src/ui/ui.cc \ ../src/ui/ui_tty.cc \ ../src/vector.cc \ ../src/work.cc fstransform-0.9.4/fsremap/build/Makefile.in000066400000000000000000000734561345021500300207010ustar00rootroot00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : sbin_PROGRAMS = fsremap$(EXEEXT) subdir = fsremap/build ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/tools/ft_cxx_flags.m4 \ $(top_srcdir)/tools/ft_cxx_features.m4 \ $(top_srcdir)/tools/ft_cxx_unordered_map.m4 \ $(top_srcdir)/tools/ft_need_funcs.m4 \ $(top_srcdir)/tools/ft_need_libs.m4 \ $(top_srcdir)/tools/ft_output.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/fsremap/src/config.hh CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" PROGRAMS = $(sbin_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_fsremap_OBJECTS = ../src/arch/mem.$(OBJEXT) \ ../src/arch/mem_linux.$(OBJEXT) \ ../src/arch/mem_posix.$(OBJEXT) ../src/args.$(OBJEXT) \ ../src/assert.$(OBJEXT) ../src/dispatch.$(OBJEXT) \ ../src/eta.$(OBJEXT) ../src/io/extent_file.$(OBJEXT) \ ../src/io/extent_posix.$(OBJEXT) ../src/io/io.$(OBJEXT) \ ../src/io/io_null.$(OBJEXT) ../src/io/io_posix.$(OBJEXT) \ ../src/io/io_posix_dir.$(OBJEXT) \ ../src/io/io_prealloc.$(OBJEXT) \ ../src/io/io_self_test.$(OBJEXT) ../src/io/io_test.$(OBJEXT) \ ../src/io/persist.$(OBJEXT) ../src/io/util_dir.$(OBJEXT) \ ../src/io/util_posix.$(OBJEXT) ../src/job.$(OBJEXT) \ ../src/log.$(OBJEXT) ../src/main.$(OBJEXT) \ ../src/map.$(OBJEXT) ../src/map_stat.$(OBJEXT) \ ../src/misc.$(OBJEXT) ../src/mstring.$(OBJEXT) \ ../src/pool.$(OBJEXT) ../src/remap.$(OBJEXT) \ ../src/tmp_zero.$(OBJEXT) ../src/ui/ui.$(OBJEXT) \ ../src/ui/ui_tty.$(OBJEXT) ../src/vector.$(OBJEXT) \ ../src/work.$(OBJEXT) fsremap_OBJECTS = $(am_fsremap_OBJECTS) fsremap_LDADD = $(LDADD) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/fsremap/src depcomp = $(SHELL) $(top_srcdir)/tools/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ../src/$(DEPDIR)/args.Po \ ../src/$(DEPDIR)/assert.Po ../src/$(DEPDIR)/dispatch.Po \ ../src/$(DEPDIR)/eta.Po ../src/$(DEPDIR)/job.Po \ ../src/$(DEPDIR)/log.Po ../src/$(DEPDIR)/main.Po \ ../src/$(DEPDIR)/map.Po ../src/$(DEPDIR)/map_stat.Po \ ../src/$(DEPDIR)/misc.Po ../src/$(DEPDIR)/mstring.Po \ ../src/$(DEPDIR)/pool.Po ../src/$(DEPDIR)/remap.Po \ ../src/$(DEPDIR)/tmp_zero.Po ../src/$(DEPDIR)/vector.Po \ ../src/$(DEPDIR)/work.Po ../src/arch/$(DEPDIR)/mem.Po \ ../src/arch/$(DEPDIR)/mem_linux.Po \ ../src/arch/$(DEPDIR)/mem_posix.Po \ ../src/io/$(DEPDIR)/extent_file.Po \ ../src/io/$(DEPDIR)/extent_posix.Po ../src/io/$(DEPDIR)/io.Po \ ../src/io/$(DEPDIR)/io_null.Po ../src/io/$(DEPDIR)/io_posix.Po \ ../src/io/$(DEPDIR)/io_posix_dir.Po \ ../src/io/$(DEPDIR)/io_prealloc.Po \ ../src/io/$(DEPDIR)/io_self_test.Po \ ../src/io/$(DEPDIR)/io_test.Po ../src/io/$(DEPDIR)/persist.Po \ ../src/io/$(DEPDIR)/util_dir.Po \ ../src/io/$(DEPDIR)/util_posix.Po ../src/ui/$(DEPDIR)/ui.Po \ ../src/ui/$(DEPDIR)/ui_tty.Po am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(fsremap_SOURCES) DIST_SOURCES = $(fsremap_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/tools/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LD_LIBCOM_ERR = @LD_LIBCOM_ERR@ LD_LIBEXT2FS = @LD_LIBEXT2FS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CXX = @ac_ct_CXX@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = subdir-objects fsremap_SOURCES = \ ../src/arch/mem.cc \ ../src/arch/mem_linux.cc \ ../src/arch/mem_posix.cc \ ../src/args.cc \ ../src/assert.cc \ ../src/dispatch.cc \ ../src/eta.cc \ ../src/io/extent_file.cc \ ../src/io/extent_posix.cc \ ../src/io/io.cc \ ../src/io/io_null.cc \ ../src/io/io_posix.cc \ ../src/io/io_posix_dir.cc \ ../src/io/io_prealloc.cc \ ../src/io/io_self_test.cc \ ../src/io/io_test.cc \ ../src/io/persist.cc \ ../src/io/util_dir.cc \ ../src/io/util_posix.cc \ ../src/job.cc \ ../src/log.cc \ ../src/main.cc \ ../src/map.cc \ ../src/map_stat.cc \ ../src/misc.cc \ ../src/mstring.cc \ ../src/pool.cc \ ../src/remap.cc \ ../src/tmp_zero.cc \ ../src/ui/ui.cc \ ../src/ui/ui_tty.cc \ ../src/vector.cc \ ../src/work.cc all: all-am .SUFFIXES: .SUFFIXES: .cc .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu fsremap/build/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu fsremap/build/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) ../src/arch/$(am__dirstamp): @$(MKDIR_P) ../src/arch @: > ../src/arch/$(am__dirstamp) ../src/arch/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) ../src/arch/$(DEPDIR) @: > ../src/arch/$(DEPDIR)/$(am__dirstamp) ../src/arch/mem.$(OBJEXT): ../src/arch/$(am__dirstamp) \ ../src/arch/$(DEPDIR)/$(am__dirstamp) ../src/arch/mem_linux.$(OBJEXT): ../src/arch/$(am__dirstamp) \ ../src/arch/$(DEPDIR)/$(am__dirstamp) ../src/arch/mem_posix.$(OBJEXT): ../src/arch/$(am__dirstamp) \ ../src/arch/$(DEPDIR)/$(am__dirstamp) ../src/$(am__dirstamp): @$(MKDIR_P) ../src @: > ../src/$(am__dirstamp) ../src/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) ../src/$(DEPDIR) @: > ../src/$(DEPDIR)/$(am__dirstamp) ../src/args.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/assert.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/dispatch.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/eta.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/io/$(am__dirstamp): @$(MKDIR_P) ../src/io @: > ../src/io/$(am__dirstamp) ../src/io/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) ../src/io/$(DEPDIR) @: > ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/io/extent_file.$(OBJEXT): ../src/io/$(am__dirstamp) \ ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/io/extent_posix.$(OBJEXT): ../src/io/$(am__dirstamp) \ ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/io/io.$(OBJEXT): ../src/io/$(am__dirstamp) \ ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/io/io_null.$(OBJEXT): ../src/io/$(am__dirstamp) \ ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/io/io_posix.$(OBJEXT): ../src/io/$(am__dirstamp) \ ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/io/io_posix_dir.$(OBJEXT): ../src/io/$(am__dirstamp) \ ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/io/io_prealloc.$(OBJEXT): ../src/io/$(am__dirstamp) \ ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/io/io_self_test.$(OBJEXT): ../src/io/$(am__dirstamp) \ ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/io/io_test.$(OBJEXT): ../src/io/$(am__dirstamp) \ ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/io/persist.$(OBJEXT): ../src/io/$(am__dirstamp) \ ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/io/util_dir.$(OBJEXT): ../src/io/$(am__dirstamp) \ ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/io/util_posix.$(OBJEXT): ../src/io/$(am__dirstamp) \ ../src/io/$(DEPDIR)/$(am__dirstamp) ../src/job.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/log.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/main.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/map.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/map_stat.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/misc.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/mstring.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/pool.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/remap.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/tmp_zero.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/ui/$(am__dirstamp): @$(MKDIR_P) ../src/ui @: > ../src/ui/$(am__dirstamp) ../src/ui/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) ../src/ui/$(DEPDIR) @: > ../src/ui/$(DEPDIR)/$(am__dirstamp) ../src/ui/ui.$(OBJEXT): ../src/ui/$(am__dirstamp) \ ../src/ui/$(DEPDIR)/$(am__dirstamp) ../src/ui/ui_tty.$(OBJEXT): ../src/ui/$(am__dirstamp) \ ../src/ui/$(DEPDIR)/$(am__dirstamp) ../src/vector.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) ../src/work.$(OBJEXT): ../src/$(am__dirstamp) \ ../src/$(DEPDIR)/$(am__dirstamp) fsremap$(EXEEXT): $(fsremap_OBJECTS) $(fsremap_DEPENDENCIES) $(EXTRA_fsremap_DEPENDENCIES) @rm -f fsremap$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(fsremap_OBJECTS) $(fsremap_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f ../src/*.$(OBJEXT) -rm -f ../src/arch/*.$(OBJEXT) -rm -f ../src/io/*.$(OBJEXT) -rm -f ../src/ui/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/args.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/assert.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/dispatch.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/eta.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/job.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/log.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/map.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/map_stat.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/misc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/mstring.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/pool.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/remap.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/tmp_zero.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/vector.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/$(DEPDIR)/work.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/arch/$(DEPDIR)/mem.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/arch/$(DEPDIR)/mem_linux.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/arch/$(DEPDIR)/mem_posix.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/io/$(DEPDIR)/extent_file.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/io/$(DEPDIR)/extent_posix.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/io/$(DEPDIR)/io.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/io/$(DEPDIR)/io_null.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/io/$(DEPDIR)/io_posix.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/io/$(DEPDIR)/io_posix_dir.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/io/$(DEPDIR)/io_prealloc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/io/$(DEPDIR)/io_self_test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/io/$(DEPDIR)/io_test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/io/$(DEPDIR)/persist.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/io/$(DEPDIR)/util_dir.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/io/$(DEPDIR)/util_posix.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/ui/$(DEPDIR)/ui.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../src/ui/$(DEPDIR)/ui_tty.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .cc.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cc.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(sbindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -rm -f ../src/$(DEPDIR)/$(am__dirstamp) -rm -f ../src/$(am__dirstamp) -rm -f ../src/arch/$(DEPDIR)/$(am__dirstamp) -rm -f ../src/arch/$(am__dirstamp) -rm -f ../src/io/$(DEPDIR)/$(am__dirstamp) -rm -f ../src/io/$(am__dirstamp) -rm -f ../src/ui/$(DEPDIR)/$(am__dirstamp) -rm -f ../src/ui/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -f ../src/$(DEPDIR)/args.Po -rm -f ../src/$(DEPDIR)/assert.Po -rm -f ../src/$(DEPDIR)/dispatch.Po -rm -f ../src/$(DEPDIR)/eta.Po -rm -f ../src/$(DEPDIR)/job.Po -rm -f ../src/$(DEPDIR)/log.Po -rm -f ../src/$(DEPDIR)/main.Po -rm -f ../src/$(DEPDIR)/map.Po -rm -f ../src/$(DEPDIR)/map_stat.Po -rm -f ../src/$(DEPDIR)/misc.Po -rm -f ../src/$(DEPDIR)/mstring.Po -rm -f ../src/$(DEPDIR)/pool.Po -rm -f ../src/$(DEPDIR)/remap.Po -rm -f ../src/$(DEPDIR)/tmp_zero.Po -rm -f ../src/$(DEPDIR)/vector.Po -rm -f ../src/$(DEPDIR)/work.Po -rm -f ../src/arch/$(DEPDIR)/mem.Po -rm -f ../src/arch/$(DEPDIR)/mem_linux.Po -rm -f ../src/arch/$(DEPDIR)/mem_posix.Po -rm -f ../src/io/$(DEPDIR)/extent_file.Po -rm -f ../src/io/$(DEPDIR)/extent_posix.Po -rm -f ../src/io/$(DEPDIR)/io.Po -rm -f ../src/io/$(DEPDIR)/io_null.Po -rm -f ../src/io/$(DEPDIR)/io_posix.Po -rm -f ../src/io/$(DEPDIR)/io_posix_dir.Po -rm -f ../src/io/$(DEPDIR)/io_prealloc.Po -rm -f ../src/io/$(DEPDIR)/io_self_test.Po -rm -f ../src/io/$(DEPDIR)/io_test.Po -rm -f ../src/io/$(DEPDIR)/persist.Po -rm -f ../src/io/$(DEPDIR)/util_dir.Po -rm -f ../src/io/$(DEPDIR)/util_posix.Po -rm -f ../src/ui/$(DEPDIR)/ui.Po -rm -f ../src/ui/$(DEPDIR)/ui_tty.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ../src/$(DEPDIR)/args.Po -rm -f ../src/$(DEPDIR)/assert.Po -rm -f ../src/$(DEPDIR)/dispatch.Po -rm -f ../src/$(DEPDIR)/eta.Po -rm -f ../src/$(DEPDIR)/job.Po -rm -f ../src/$(DEPDIR)/log.Po -rm -f ../src/$(DEPDIR)/main.Po -rm -f ../src/$(DEPDIR)/map.Po -rm -f ../src/$(DEPDIR)/map_stat.Po -rm -f ../src/$(DEPDIR)/misc.Po -rm -f ../src/$(DEPDIR)/mstring.Po -rm -f ../src/$(DEPDIR)/pool.Po -rm -f ../src/$(DEPDIR)/remap.Po -rm -f ../src/$(DEPDIR)/tmp_zero.Po -rm -f ../src/$(DEPDIR)/vector.Po -rm -f ../src/$(DEPDIR)/work.Po -rm -f ../src/arch/$(DEPDIR)/mem.Po -rm -f ../src/arch/$(DEPDIR)/mem_linux.Po -rm -f ../src/arch/$(DEPDIR)/mem_posix.Po -rm -f ../src/io/$(DEPDIR)/extent_file.Po -rm -f ../src/io/$(DEPDIR)/extent_posix.Po -rm -f ../src/io/$(DEPDIR)/io.Po -rm -f ../src/io/$(DEPDIR)/io_null.Po -rm -f ../src/io/$(DEPDIR)/io_posix.Po -rm -f ../src/io/$(DEPDIR)/io_posix_dir.Po -rm -f ../src/io/$(DEPDIR)/io_prealloc.Po -rm -f ../src/io/$(DEPDIR)/io_self_test.Po -rm -f ../src/io/$(DEPDIR)/io_test.Po -rm -f ../src/io/$(DEPDIR)/persist.Po -rm -f ../src/io/$(DEPDIR)/util_dir.Po -rm -f ../src/io/$(DEPDIR)/util_posix.Po -rm -f ../src/ui/$(DEPDIR)/ui.Po -rm -f ../src/ui/$(DEPDIR)/ui_tty.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-sbinPROGRAMS cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-sbinPROGRAMS .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: fstransform-0.9.4/fsremap/src/000077500000000000000000000000001345021500300163055ustar00rootroot00000000000000fstransform-0.9.4/fsremap/src/arch/000077500000000000000000000000001345021500300172225ustar00rootroot00000000000000fstransform-0.9.4/fsremap/src/arch/mem.cc000066400000000000000000000032031345021500300203050ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * arch/mem.cc * * Created on: Mar 10, 2011 * Author: max */ #include "../first.hh" #include "mem.hh" // for ff_arch_mem_system_free(), ff_arch_mem_page_size() #include "mem_posix.hh" // for ff_arch_posix_mem_page_size() #include "mem_linux.hh" // for ff_arch_linux_mem_system_free() FT_ARCH_NAMESPACE_BEGIN /** * return an approximation of free system memory in bytes, * or 0 if cannot be determined */ ft_uoff ff_arch_mem_system_free() { #if defined(__linux__) return ff_arch_linux_mem_system_free(); #else return 0; #endif } /** * return RAM page size, or 0 if cannot be determined */ ft_size ff_arch_mem_page_size() { #if defined(__unix__) return ff_arch_posix_mem_page_size(); #else return 0; #endif } FT_ARCH_NAMESPACE_END fstransform-0.9.4/fsremap/src/arch/mem.hh000066400000000000000000000025151345021500300203240ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * arch/mem.hh * * Created on: Mar 10, 2011 * Author: max */ #ifndef FSREMAP_ARCH_MEM_HH #define FSREMAP_ARCH_MEM_HH #include "../types.hh" FT_ARCH_NAMESPACE_BEGIN /** * return an approximation of free system memory in bytes, * or 0 if cannot be determined */ ft_uoff ff_arch_mem_system_free(); /** * return RAM page size, or 0 if cannot be determined */ ft_size ff_arch_mem_page_size(); FT_ARCH_NAMESPACE_END #endif /* FSREMAP_ARCH_MEM_HH */ fstransform-0.9.4/fsremap/src/arch/mem_linux.cc000066400000000000000000000070121345021500300215260ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * arch/mem_linux.cc * * Created on: Mar 10, 2011 * Author: max */ #include "../first.hh" #ifdef __linux__ #include "mem_linux.hh" #if defined(FT_HAVE_ERRNO_H) # include // for errno #elif defined(FT_HAVE_CERRNO) # include // for errno #endif #if defined(FT_HAVE_STDIO_H) # include // for FILE, fopen(), fclose() #elif defined(FT_HAVE_CSTDIO) # include // for FILE, fopen(), fclose() #endif #if defined(FT_HAVE_STRING_H) # include // for strcmp() #elif defined(FT_HAVE_CSTRING) # include // for strcmp() #endif #include "../log.hh" // for ff_log() FT_ARCH_NAMESPACE_BEGIN /** * return an approximation of free system memory in bytes, * or 0 if cannot be determined */ ft_uoff ff_arch_linux_mem_system_free() { FILE * f = fopen("/proc/meminfo", "r"); if (f == NULL) { ff_log(FC_WARN, errno, "failed to open /proc/meminfo, maybe /proc is not mounted?"); return 0; } char label[256], unit[8]; ft_ull n_ull = 0, scale; ft_uoff total = 0, n; ft_uint left = 3; int err; while (left != 0) { if ((err = fscanf(f, "%256s %" FT_ULL " %8s\n", label, & n_ull, unit)) <= 0) { if (ferror(f)) ff_log(FC_WARN, errno, "error reading /proc/meminfo"); break; } if (err != 3) continue; label[255] = '\0'; // in case it's missing unit[7] = '\0'; // idem if (strcmp(label, "MemFree:") && strcmp(label, "Buffers:") && strcmp(label, "Cached:")) continue; switch (unit[0]) { case 'k': scale = 10; break; // 2^10 = 1k case 'M': scale = 20; break; // 2^20 = 1M case 'G': scale = 30; break; // 2^30 = 1G case 'T': scale = 40; break; // 2^40 = 1T case 'P': scale = 50; break; // 2^50 = 1P case 'E': scale = 60; break; // 2^60 = 1E case 'Z': scale = 70; break; // 2^70 = 1Z case 'Y': scale = 80; break; // 2^80 = 1Y default: scale = 0; break; } /* overflow? then approximate.. */ if (scale >= 8*sizeof(ft_ull) || n_ull > (ft_ull)-1 >> scale) n_ull = (ft_ull)-1; else n_ull <<= scale; n = (ft_uoff) n_ull; /* overflow? then approximate.. */ if ((ft_ull) n != n_ull || n > (ft_uoff)-1 - total) { total = (ft_uoff)-1; break; } total += n; left--; } if (fclose(f) != 0) ff_log(FC_WARN, errno, "error closing /proc/meminfo"); return total; } FT_ARCH_NAMESPACE_END #endif /* __linux__ */ fstransform-0.9.4/fsremap/src/arch/mem_linux.hh000066400000000000000000000024651345021500300215470ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * arch/mem_linux.hh * * Created on: Mar 10, 2011 * Author: max */ #ifndef FSREMAP_ARCH_MEM_LINUX_HH #define FSREMAP_ARCH_MEM_LINUX_HH #include "../types.hh" #ifdef __linux__ FT_ARCH_NAMESPACE_BEGIN /** * return an approximation of free system memory in bytes, * or 0 if cannot be determined */ ft_uoff ff_arch_linux_mem_system_free(); FT_ARCH_NAMESPACE_END #endif /* __linux__ */ #endif /* FSREMAP_ARCH_MEM_LINUX_HH */ fstransform-0.9.4/fsremap/src/arch/mem_posix.cc000066400000000000000000000034721345021500300215370ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * arch/mem_posix.cc * * Created on: Mar 11, 2011 * Author: max */ #include "../first.hh" #ifdef __unix__ #ifdef FT_HAVE_UNISTD_H # include // for sysconf(), _SC_PAGESIZE #endif #include "mem_posix.hh" FT_ARCH_NAMESPACE_BEGIN /** * return RAM page size, or 0 if cannot be determined */ ft_size ff_arch_posix_mem_page_size() { // first attempt: sysconf(_SC_PAGESIZE) #if defined(FT_HAVE_SYSCONF) && defined(_SC_PAGESIZE) long n = sysconf(_SC_PAGESIZE); if (n > 0 && n == (long)(ft_size) n) return (ft_size) n; #endif // second attempt: getpagesize() #if defined(FT_HAVE_GETPAGESIZE) int n2 = getpagesize(); if (n2 > 0 && n2 == (int)(ft_size) n2) return (ft_size) n2; #endif // third attempt: PAGE_SIZE and PAGESIZE #if defined(PAGE_SIZE) return PAGE_SIZE; #elif defined(PAGESIZE) return PAGESIZE; #else return 0; #endif } FT_ARCH_NAMESPACE_END #endif /* __unix__ */ fstransform-0.9.4/fsremap/src/arch/mem_posix.hh000066400000000000000000000024151345021500300215450ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * arch/mem_posix.hh * * Created on: Mar 11, 2011 * Author: max */ #ifndef FSREMAP_ARCH_MEM_POSIX_HH #define FSREMAP_ARCH_MEM_POSIX_HH #include "../types.hh" #ifdef __unix__ FT_ARCH_NAMESPACE_BEGIN /** * return RAM page size, or 0 if cannot be determined */ ft_size ff_arch_posix_mem_page_size(); FT_ARCH_NAMESPACE_END #endif /* __unix__ */ #endif /* FSREMAP_ARCH_MEM_POSIX_HH */ fstransform-0.9.4/fsremap/src/args.cc000066400000000000000000000034001345021500300175450ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * args.cc * * Created on: Mar 21, 2011 * Author: max */ #include "first.hh" #include "args.hh" // for fr_args FT_NAMESPACE_BEGIN /** default constructor */ fr_args::fr_args() : program_name("fsremap"), root_dir(NULL), io_args(), mount_points(), loop_dev(NULL), ui_arg(NULL), cmd_losetup(NULL), cmd_umount(NULL), storage_size(), job_id(FC_JOB_ID_AUTODETECT), job_clear(FC_CLEAR_AUTODETECT), io_kind(FC_IO_AUTODETECT), ui_kind(FC_UI_NONE), force_run(false), simulate_run(false), ask_questions(false) { ft_size i, n; for (i = 0, n = sizeof(io_args)/sizeof(io_args[0]); i < n; i++) io_args[i] = NULL; for (i = 0, n = sizeof(mount_points)/sizeof(mount_points[0]); i < n; i++) mount_points[i] = NULL; for (i = 0, n = sizeof(storage_size)/sizeof(storage_size[0]); i < n; i++) storage_size[i] = 0; } FT_NAMESPACE_END fstransform-0.9.4/fsremap/src/args.hh000066400000000000000000000057531345021500300175740ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * main.hh * * Created on: Mar 20, 2011 * Author: max */ #ifndef FSREMAP_ARGS_HH #define FSREMAP_ARGS_HH #include "types.hh" // for ft_uint, ft_size FT_NAMESPACE_BEGIN enum fr_storage_size { FC_MEM_BUFFER_SIZE, FC_SECONDARY_STORAGE_SIZE, FC_PRIMARY_STORAGE_EXACT_SIZE, FC_SECONDARY_STORAGE_EXACT_SIZE, FC_STORAGE_SIZE_N, }; enum fr_clear_free_space { FC_CLEAR_AUTODETECT, FC_CLEAR_ALL, FC_CLEAR_MINIMAL, FC_CLEAR_NONE, }; enum fr_job_id_kind { FC_JOB_ID_AUTODETECT = 0 }; enum fr_io_kind { FC_IO_AUTODETECT, FC_IO_TEST, FC_IO_SELF_TEST, FC_IO_POSIX, FC_IO_PREALLOC }; enum fr_mount_points { FC_MOUNT_POINT_DEVICE = 0, FC_MOUNT_POINT_LOOP_FILE, FC_MOUNT_POINTS_N }; enum fr_ui_kind { FC_UI_NONE, FC_UI_TTY }; class fr_args { public: const char * program_name; // detected from command line. default: "fsremap" const char * root_dir; // write logs and persistence files inside this folder. if NULL, will autodetect const char * io_args[3]; // some I/O will need less than 3 arguments const char * mount_points[FC_MOUNT_POINTS_N]; // device and loop file mount points. currently only needed by fr_io_prealloc const char * loop_dev; // loop device. currently only needed by fr_io_prealloc const char * ui_arg; const char * cmd_losetup; // 'losetup' command. currently only needed by fr_io_prealloc const char * cmd_umount; ft_size storage_size[FC_STORAGE_SIZE_N]; // if 0, will autodetect ft_uint job_id; // if FC_JOB_ID_AUTODETECT, will autodetect fr_clear_free_space job_clear; fr_io_kind io_kind; // if FC_IO_AUTODETECT, will autodetect fr_ui_kind ui_kind; bool force_run; // if true, some sanity checks will be WARNINGS instead of ERRORS bool simulate_run; // if true, remapping algorithm runs WITHOUT reading or writing device blocks bool ask_questions; // if true, remapping algorithm will ask confirmation and read answer from stdin before actually starting fr_args(); }; FT_NAMESPACE_END #endif /* FSREMAP_ARGS_HH */ fstransform-0.9.4/fsremap/src/assert.cc000066400000000000000000000030551345021500300201200ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * assert.cc * * Created on: Mar 13, 2011 * Author: max */ #include "first.hh" #if defined(FT_HAVE_STDLIB_H) # include // for exit() #elif defined(FT_HAVE_CSTDLIB) # include // for exit() #endif #include "assert.hh" // for ff_assert() #include "log.hh" // for ff_log() FT_NAMESPACE_BEGIN void ff_assert_fail0(const char * caller_file, int caller_file_len, const char * caller_func, int caller_line, const char * assertion) { ff_logl(caller_file, caller_file_len, caller_func, caller_line, FC_FATAL, 0, "internal error! assertion failed: %s", assertion); ft_log_appender::flush_all(FC_FATAL); exit(1); } FT_NAMESPACE_END fstransform-0.9.4/fsremap/src/assert.hh000066400000000000000000000030301345021500300201230ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * assert.h * * Created on: Feb 27, 2011 * Author: max */ #ifndef FSTRANSFORM_ASSERT_HH #define FSTRANSFORM_ASSERT_HH #include "check.hh" FT_EXTERN_C_BEGIN FT_NAMESPACE_BEGIN void ff_assert_fail0(const char * caller_file, int caller_file_len, const char * caller_func, int caller_line, const char * assertion); FT_NAMESPACE_END FT_EXTERN_C_END #define ff_assert(expr) do { if (!(expr)) ff_assert_fail0(FT_THIS_FILE, sizeof(FT_THIS_FILE)-1, FT_THIS_FUNCTION, FT_THIS_LINE, #expr ); } while (0) #define ff_assert_fail(msg) ff_assert_fail0(FT_THIS_FILE, sizeof(FT_THIS_FILE)-1, FT_THIS_FUNCTION, FT_THIS_LINE, (msg)) #endif /* FSTRANSFORM_ASSERT_HH */ fstransform-0.9.4/fsremap/src/autoconf.hh000066400000000000000000000067661345021500300204630ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * autoconf.hh * * defines compiler, headers and library features. * * Created on: Feb 27, 2011 * Author: max */ #ifndef FSTRANSFORM_AUTOCONF_HH #define FSTRANSFORM_AUTOCONF_HH #include "check.hh" #include "ft_config.hh" /** * define if C++ library implements something usable for ft_unsorted_map * possibilities include: std::unordered_map and std::tr1::unordered_map */ #if !defined(FT_HAVE_FT_UNSORTED_MAP) && (defined(FT_HAVE_STD_UNORDERED_MAP) || defined(FT_HAVE_STD_TR1_UNORDERED_MAP)) # define FT_HAVE_FT_UNSORTED_MAP #endif /** define if compiler supports the types (long long) and (unsigned long long) */ #if !defined(FT_HAVE_LONG_LONG) || !defined(FT_HAVE_UNSIGNED_LONG_LONG) # if defined(__GNUC__) # define FT_HAVE_LONG_LONG # define FT_HAVE_UNSIGNED_LONG_LONG # endif #endif /* FT_HAVE_LONG_LONG */ /* (long long) and (unsigned long long) are useful only if they are BOTH supported */ #ifndef FT_HAVE_LONG_LONG # undef FT_HAVE_UNSIGNED_LONG_LONG #endif #ifndef FT_HAVE_UNSIGNED_LONG_LONG # undef FT_HAVE_LONG_LONG #endif /** define if va_copy() macro is supported (copies va_list variadic arguments) */ #ifndef FT_HAVE_VA_COPY # if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L # define FT_HAVE_VA_COPY # endif #endif /** define to compiler's own version of 'inline' keyword */ #ifndef FT_INLINE # if defined(__cplusplus) /* inline is standard keyword in C++ */ # define FT_INLINE inline # elif defined(__GNUC__) /* prefer __inline__ to inline, the former works even in gcc strict-ansi mode */ # define FT_INLINE __inline__ # else # define FT_INLINE # endif #endif /* FT_INLINE */ /** * define if extern "C" { ... } is understood by the compiler and needed to get C linkage. * should be defined in C++, and undefined in C. */ #ifndef FT_HAVE_EXTERN_C # if defined(__cplusplus) # define FT_HAVE_EXTERN_C # endif #endif /* FT_HAVE_EXTERN_C */ /** * define if namespace Foo { ... } is understood by the compiler. * should be defined in C++, and undefined in C. */ #ifndef FT_HAVE_NAMESPACE # if defined(__cplusplus) # define FT_HAVE_NAMESPACE # endif #endif /* FT_HAVE_NAMESPACE */ /** define to compiler's own version of __FILE__ or equivalent */ #ifndef FT_THIS_FILE # define FT_THIS_FILE __FILE__ #endif /** define to compiler's own version of __LINE__ or equivalent */ #ifndef FT_THIS_LINE # define FT_THIS_LINE __LINE__ #endif /** define to compiler's own version of __func__, __FUNCTION__ or equivalent (don't use __PRETTY_FUNCTION__) */ #ifndef FT_THIS_FUNCTION # define FT_THIS_FUNCTION __FUNCTION__ #endif #endif /* FSTRANSFORM_AUTOCONF_HH */ fstransform-0.9.4/fsremap/src/cache/000077500000000000000000000000001345021500300173505ustar00rootroot00000000000000fstransform-0.9.4/fsremap/src/cache/cache.hh000066400000000000000000000051611345021500300207370ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * cache.hh * * Created on: Aug 18, 2011 * Author: max */ #ifndef FSTRANSFORM_CACHE_HH #define FSTRANSFORM_CACHE_HH FT_NAMESPACE_BEGIN /* * Base class for generic key->value caches. * * Used to implement inode cache, needed to detect multiple files * hard-linked together (i.e. having the same inode) and let fsmove * create an accurate replica of them. */ template class ft_cache { protected: V zero_payload; public: /** default constructor */ ft_cache(const V & init_zero_payload = V()) : zero_payload(init_zero_payload) { } /** copy constructor */ ft_cache(const ft_cache & other) : zero_payload(other.zero_payload) { } /** assignment operator */ virtual const ft_cache & operator=(const ft_cache & other) { if (this != &other) zero_payload = other.zero_payload; return *this; } /** destructor */ virtual ~ft_cache() { } /** * if cached inode found, set payload and return 1. * Otherwise add it to cache and return 0. * On error, return < 0. * if returns 0, find_and_delete() must be called on the same inode when done with payload! */ virtual int find_or_add(const K key, V & inout_payload) = 0; /** * if cached inode found, set result_payload, remove inode from cache and return 1. * Otherwise return 0. On error, return < 0. */ virtual int find_and_delete(const K key, V & result_payload) = 0; /** * if cached inode found, change its payload and return 1. * Otherwise return 0. On error, return < 0. */ virtual int find_and_update(const K key, const V & new_payload) = 0; virtual void clear() = 0; }; FT_NAMESPACE_END #endif /* FSTRANSFORM_CACHE_HH */ fstransform-0.9.4/fsremap/src/cache/cache_adaptor.hh000066400000000000000000000072211345021500300224500ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * inode_cache.hh * * Created on: Aug 18, 2011 * Author: max */ #ifndef FSTRANSFORM_CACHE_ADAPTOR_HH #define FSTRANSFORM_CACHE_ADAPTOR_HH #include "cache.hh" // for ft_cache #include "../copy.hh" // for ff_set() FT_NAMESPACE_BEGIN /** * adaptor from string->string caches to K->V caches. * * Used to wrap ft_cache_symlink and tranform it into ft_cache_symlink_kv * - see cache_symlink.hh for details. */ template class ft_cache_adaptor : public ft_cache, public Cache { private: typedef ft_cache super_type; typedef ft_cache_adaptor this_type; typedef Cache mixin_type; typedef typename Cache::key_type mixin_key_type; typedef typename Cache::payload_type mixin_payload_type; public: /** default constructor */ ft_cache_adaptor(const V & init_zero_payload = V()) : super_type(init_zero_payload), mixin_type() { } /** copy constructor */ ft_cache_adaptor(const this_type & other) : super_type(other), mixin_type(other) { } /** assignment operator */ virtual const super_type & operator=(const this_type & other) { mixin_type::operator=(other); return super_type::operator=(other); } /** destructor */ virtual ~ft_cache_adaptor() { } /** * if cached inode found, set payload and return 1. * Otherwise add it to cache and return 0. * On error, return < 0. * if returns 0, erase() must be called on the same inode when done with payload! */ virtual int find_or_add(const K key, V & inout_payload) { mixin_key_type m_key; ff_set(m_key, key); mixin_payload_type m_payload; ff_set(m_payload, inout_payload); int err = mixin_type::find_or_add(m_key, m_payload); ff_set(inout_payload, m_payload); return err; } /** * if cached key found, set payload, remove cached key and return 1. * Otherwise return 0. On error, return < 0. */ virtual int find_and_delete(const K key, V & result_payload) { mixin_key_type m_key; ff_set(m_key, key); mixin_payload_type m_payload; int err = mixin_type::find_and_delete(m_key, m_payload); ff_set(result_payload, m_payload); return err; } /** * if cached inode found, change its payload and return 1. * Otherwise return 0. On error, return < 0. */ virtual int find_and_update(const K key, const V & new_payload) { mixin_key_type m_key; ff_set(m_key, key); mixin_payload_type m_payload; ff_set(m_payload, new_payload); return mixin_type::find_and_update(m_key, m_payload); } virtual void clear() { mixin_type::clear(); } }; FT_NAMESPACE_END #endif /* FSTRANSFORM_CACHE_ADAPTOR_HH */ fstransform-0.9.4/fsremap/src/cache/cache_mem.hh000066400000000000000000000071601345021500300215760ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * inode_cache.hh * * Created on: Aug 18, 2011 * Author: max */ #ifndef FSTRANSFORM_CACHE_MEM_HH #define FSTRANSFORM_CACHE_MEM_HH #include "../assert.hh" // for ff_assert() #include "cache.hh" // for ft_cache #ifdef FT_HAVE_FT_UNSORTED_MAP # include "unsorted_map.hh" // for ft_unsorted_map #else # include // for std::map #endif FT_NAMESPACE_BEGIN /** * in-memory associative array from keys (type K) to values (type V). * Used to implement inode cache - see cache.hh for details. */ template class ft_cache_mem : public ft_cache { private: typedef ft_cache super_type; #ifdef FT_HAVE_FT_UNSORTED_MAP typedef ft_unsorted_map map_type; #else typedef std::map map_type; #endif map_type map; public: /** default constructor */ ft_cache_mem(const V & init_zero_payload = V()) : super_type(init_zero_payload), map() { } /** copy constructor */ ft_cache_mem(const ft_cache_mem & other) : super_type(other), map(other.map) { } /** assignment operator */ virtual const super_type & operator=(const ft_cache_mem & other) { if (this != &other) map = other.map; return super_type::operator=(other); } /** destructor */ virtual ~ft_cache_mem() { } /** * if cached inode found, set payload and return 1. * Otherwise add it to cache and return 0. * On error, return < 0. * if returns 0, erase() must be called on the same inode when done with payload! */ virtual int find_or_add(const K key, V & inout_payload) { ff_assert(inout_payload != this->zero_payload); V & value = map[key]; if (value == this->zero_payload) { value = inout_payload; return 0; } inout_payload = value; return 1; } /** * if cached key found, set result_payload, remove cached key and return 1. * Otherwise return 0. On error, return < 0. */ virtual int find_and_delete(const K key, V & result_payload) { typename map_type::iterator iter = map.find(key); if (iter == map.end()) return 0; result_payload = iter->second; map.erase(iter); return 1; } /** * if cached inode found, change its payload and return 1. * Otherwise return 0. On error, return < 0. */ virtual int find_and_update(const K key, const V & new_payload) { typename map_type::iterator iter = map.find(key); if (iter == map.end()) return 0; iter->second = new_payload; return 1; } virtual void clear() { map.clear(); } }; FT_NAMESPACE_END #endif /* FSTRANSFORM_CACHE_MEM_HH */ fstransform-0.9.4/fsremap/src/cache/cache_symlink.cc000066400000000000000000000146131345021500300224750ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/extent_file.cc * * Created on: Mar 3, 2011 * Author: max */ #include "../first.hh" #if defined(FT_HAVE_ERRNO_H) # include // for errno #elif defined(FT_HAVE_CERRNO) # include // for errno #endif #ifdef FT_HAVE_UNISTD_H # include #endif #include "log.hh" #include "cache_symlink.hh" #include "../assert.hh" // for ff_assert() #include "../copy.hh" // for ff_cat() #include "../io/util_dir.hh" // for ff_mkdir_recursive(), ff_remove_recursive() FT_NAMESPACE_BEGIN /** one-arg constructor */ ft_cache_symlink::ft_cache_symlink() { } /** copy constructor */ ft_cache_symlink::ft_cache_symlink(const ft_cache_symlink & other) : path(other.path) { } /** assignment operator */ const ft_cache_symlink & ft_cache_symlink::operator=(const ft_cache_symlink & other) { if (this != &other) path = other.path; return *this; } /** destructor */ ft_cache_symlink::~ft_cache_symlink() { ft_cache_symlink::clear(); } /* initialize the inode-cache. return 0 on success, else return error */ int ft_cache_symlink::init(const ft_string & init_path) { int err = FT_IO_NS ff_mkdir_recursive(init_path); if (err != 0) { // EEXIST is a warning, everything else is an error bool exists = err == EEXIST; err = ff_log(exists ? FC_WARN : FC_ERROR, err, "failed to create cache directory `%s'", init_path.c_str()); if (exists) err = 0; } if (err == 0) { path = init_path; /* * comply with get_path() promise: * remove trailing '/' unless it's exactly the path "/" */ size_t len = path.length(); if (len > 1 && path[len-1] == '/') path.resize(len - 1); } return err; } int ft_cache_symlink::build_path(const ft_string & rel, ft_string & abs, FT_ICP_OPTIONS options) const { size_t len = rel.length(); ff_assert(len != 0); size_t len_1 = len - 1, depth = len_1 / 3, mod_3p1 = (len_1 % 3) + 1; int err = 0; abs = path; // add trailing '/' if needed if (!abs.empty() && *abs.rbegin() != '/') abs += '/'; // add prefix 'L' + depth +'/' abs += 'L'; ff_cat(abs, depth); if (options == FT_ICP_READWRITE) err = FT_IO_NS ff_mkdir_or_warn(abs.c_str()); abs += '/'; // add 1-3 chars prefix taken from beginning of rel abs += rel.substr(0, mod_3p1); // add rest of rel in 3-chars steps for (size_t i = 0; i < depth; i++) { if (options == FT_ICP_READWRITE) { err = FT_IO_NS ff_mkdir_or_warn(abs.c_str()); } abs += '/'; abs += rel.substr(mod_3p1 + i * 3, 3); } return err == EEXIST ? 0 : err; } int ft_cache_symlink::readlink(const ft_string & src, ft_string & dst) { size_t orig_len = dst.length(), len = orig_len < 256 ? 256 : orig_len; ssize_t got; again: dst.resize(len); got = ::readlink(src.c_str(), &dst[0], len); if (got > 0 && (size_t)got == len) { len *= 2; goto again; } if (got < 0) { // not found, or other error: restore dst. dst.resize(orig_len); int err = errno; if (err != ENOENT) err = ff_log(FC_ERROR, err, "failed to read cache symlink `%s'", src.c_str()); return err; } dst.resize(got); return 0; } /** * if cached inode found, set payload and return 1. * Otherwise add it to cache and return 0. * On error, return < 0. * if returns 0, find_and_delete() must be called on the same inode when done with payload! */ int ft_cache_symlink::find_or_add(const ft_string & inode, ft_string & payload) { ft_string link_from; build_path(inode, link_from, FT_ICP_READWRITE); int err = readlink(link_from, payload); if (err == 0) // found return 1; if (::symlink(payload.c_str(), link_from.c_str()) != 0) return ff_log(FC_ERROR, errno, "failed to create cache symlink `%s' -> `%s'", link_from.c_str(), payload.c_str()); return 0; } /** * if cached inode found, set payload, remove cached inode and return 1. * Otherwise return 0. On error, return < 0. */ int ft_cache_symlink::find_and_delete(const ft_string & inode, ft_string & result_payload) { ft_string link_from; build_path(inode, link_from, FT_ICP_READONLY); int err = readlink(link_from, result_payload); if (err == ENOENT) // not found return 0; if (err != 0) ff_log(FC_WARN, errno, "failed to read cache symlink `%s'", link_from.c_str()); // either found, or error if (::unlink(link_from.c_str()) != 0) ff_log(FC_WARN, errno, "failed to remove cache symlink `%s'", link_from.c_str()); return err == 0 ? 1 : err; } /** * if cached inode found, change its payload and return 1. * Otherwise return 0. On error, return < 0. */ int ft_cache_symlink::find_and_update(const ft_string inode, const ft_string & new_payload) { ft_string link_from; build_path(inode, link_from, FT_ICP_READONLY); int err = ::unlink(link_from.c_str()); if (err == ENOENT) // not found return 0; if (err != 0) ff_log(FC_WARN, errno, "failed to remove cache symlink `%s'", link_from.c_str()); // either found, or warning if (::symlink(new_payload.c_str(), link_from.c_str()) != 0) return ff_log(FC_ERROR, errno, "failed to create cache symlink `%s' -> `%s'", link_from.c_str(), new_payload.c_str()); return 1; } void ft_cache_symlink::clear() { FT_IO_NS ff_remove_recursive(path); } FT_NAMESPACE_END fstransform-0.9.4/fsremap/src/cache/cache_symlink.hh000066400000000000000000000072561345021500300225140ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * key_cache.hh * * Created on: Aug 18, 2011 * Author: max */ #ifndef FSTRANSFORM_CACHE_SYMLINK_HH #define FSTRANSFORM_CACHE_SYMLINK_HH #include "cache_adaptor.hh" // for ft_cache_adaptor #include // for std::map FT_NAMESPACE_BEGIN /** * symlink-based associative array from keys (strings) to values (strings). * Used to implement inode cache - see cache.hh for details. */ class ft_cache_symlink { protected: ft_string path; enum FT_ICP_OPTIONS { FT_ICP_READONLY, FT_ICP_READWRITE }; static int readlink(const ft_string & src, ft_string & dst); int build_path(const ft_string & rel, ft_string & abs, FT_ICP_OPTIONS options) const; public: typedef ft_string key_type; typedef ft_string payload_type; /** one-arg constructor */ explicit ft_cache_symlink(); /** copy constructor */ ft_cache_symlink(const ft_cache_symlink & other); /** assignment operator */ const ft_cache_symlink & operator=(const ft_cache_symlink & other); /** destructor */ virtual ~ft_cache_symlink(); /* guaranteed NOT to end with '/', unless it's exactly the path "/" */ const char * get_path() const { return path.c_str(); } /* initialize the cache. return 0 on success, else return error */ int init(const ft_string & init_path); /** * if cached key found, set payload and return 1. * Otherwise add it to cache and return 0. * On error, return < 0. * if returns 0, erase() must be called on the same key when done with payload! */ int find_or_add(const ft_string & key, ft_string & payload); /** * if cached key found, set result_payload, remove cached key and return 1. * Otherwise return 0. On error, return < 0. */ int find_and_delete(const ft_string & key, ft_string & result_payload); /** * if cached inode found, change its payload and return 1. * Otherwise return 0. On error, return < 0. */ int find_and_update(const ft_string key, const ft_string & new_payload); void clear(); }; /** * symlink-based associative array from keys (type K) to values (type V). * Used to implement inode cache - see cache.hh for details. */ template class ft_cache_symlink_kv : public ft_cache_adaptor { private: typedef ft_cache_symlink mixin_type; typedef ft_cache_adaptor super_type; public: /** default constructor */ ft_cache_symlink_kv(const V & init_zero_payload = V()) : super_type(init_zero_payload) { } /** destructor */ virtual ~ft_cache_symlink_kv() { } /* initialize the cache. return 0 on success, else return error */ int init(const V & path) { ft_string s_path; ff_set(s_path, path); return mixin_type::init(s_path); } }; FT_NAMESPACE_END #endif /* FSTRANSFORM_CACHE_SYMLINK_HH */ fstransform-0.9.4/fsremap/src/check.hh000066400000000000000000000017371345021500300177130ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . */ #ifndef FSTRANSFORM_FIRST_HH # error "first.hh" must be included before any other #include #endif fstransform-0.9.4/fsremap/src/config.hh.in000066400000000000000000000253401345021500300205040ustar00rootroot00000000000000/* fsremap/src/config.hh.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have the header file. */ #undef HAVE_CERRNO /* Define to 1 if you have the `chown' function. */ #undef HAVE_CHOWN /* Define to 1 if you have the header file. */ #undef HAVE_CLIMITS /* Define to 1 if you have the header file. */ #undef HAVE_CMATH /* Define to 1 if you have the header file. */ #undef HAVE_CSTDARG /* Define to 1 if you have the header file. */ #undef HAVE_CSTDIO /* Define to 1 if you have the header file. */ #undef HAVE_CSTDLIB /* Define to 1 if you have the header file. */ #undef HAVE_CSTRING /* Define to 1 if you have the header file. */ #undef HAVE_CTIME /* Define to 1 if you have the header file. */ #undef HAVE_DIRENT_H /* Define to 1 if you have the header file. */ #undef HAVE_ERRNO_H /* Define to 1 if you have the `execvp' function. */ #undef HAVE_EXECVP /* Define to 1 if you have the header file. */ #undef HAVE_EXT2FS_EXT2FS_H /* define if C++ compiler supports forcing and inhibiting template instantiation */ #undef HAVE_EXTERN_TEMPLATE /* Define to 1 if you have the `fallocate' function. */ #undef HAVE_FALLOCATE /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the `fdatasync' function. */ #undef HAVE_FDATASYNC /* Define to 1 if you have the header file. */ #undef HAVE_FEATURES_H /* Define to 1 if you have the `fileno' function. */ #undef HAVE_FILENO /* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK /* Define to 1 if you have the `fsync' function. */ #undef HAVE_FSYNC /* Define to 1 if you have the `ftruncate' function. */ #undef HAVE_FTRUNCATE /* Define to 1 if you have the `getpagesize' function. */ #undef HAVE_GETPAGESIZE /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY /* Define to 1 if you have the `getuid' function. */ #undef HAVE_GETUID /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if "prealloc" I/O is supported" */ #undef HAVE_IO_PREALLOC /* Define to 1 if you have the `isatty' function. */ #undef HAVE_ISATTY /* Define to 1 if you have the `lchown' function. */ #undef HAVE_LCHOWN /* Define to 1 if you have the com_err library. */ #undef HAVE_LIBCOM_ERR /* Define to 1 if you have the ext2fs library. */ #undef HAVE_LIBEXT2FS /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_FIEMAP_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_FS_H /* Define to 1 if you have the `localtime' function. */ #undef HAVE_LOCALTIME /* Define to 1 if you have the `localtime_r' function. */ #undef HAVE_LOCALTIME_R /* Define to 1 if the system has the type `long long'. */ #undef HAVE_LONG_LONG /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #undef HAVE_MALLOC /* Define to 1 if you have the header file. */ #undef HAVE_MATH_H /* Define to 1 if you have the `memmove' function. */ #undef HAVE_MEMMOVE /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET /* Define to 1 if you have the `mkdir' function. */ #undef HAVE_MKDIR /* Define to 1 if you have the `mkfifo' function. */ #undef HAVE_MKFIFO /* Define to 1 if you have the `mlock' function. */ #undef HAVE_MLOCK /* Define to 1 if you have a working `mmap' system call. */ #undef HAVE_MMAP /* Define to 1 if you have the `mount' function. */ #undef HAVE_MOUNT /* Define to 1 if you have the `msync' function. */ #undef HAVE_MSYNC /* Define to 1 if you have the `munmap' function. */ #undef HAVE_MUNMAP /* Define to 1 if you have the `posix_fallocate' function. */ #undef HAVE_POSIX_FALLOCATE /* Define to 1 if you have the `random' function. */ #undef HAVE_RANDOM /* Define to 1 if you have the `remove' function. */ #undef HAVE_REMOVE /* Define to 1 if you have the `srandom' function. */ #undef HAVE_SRANDOM /* Define to 1 if you have the header file. */ #undef HAVE_STDARG_H /* Define to 1 if you have the header file. */ #undef HAVE_STDDEF_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* define if C++ library implements std::tr1::unordered_map */ #undef HAVE_STD_TR1_UNORDERED_MAP /* define if C++ library implements std::unordered_map */ #undef HAVE_STD_UNORDERED_MAP /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have the `strftime' function. */ #undef HAVE_STRFTIME /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if `d_secperunit' is a member of `struct disklabel'. */ #undef HAVE_STRUCT_DISKLABEL_D_SECPERUNIT /* Define to 1 if `d_secsize' is a member of `struct disklabel'. */ #undef HAVE_STRUCT_DISKLABEL_D_SECSIZE /* Define to 1 if `st_atimensec' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_ATIMENSEC /* Define to 1 if `st_atim.tv_nsec' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC /* Define to 1 if `st_mtimensec' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_MTIMENSEC /* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC /* Define to 1 if `st_rdev' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_RDEV /* Define to 1 if you have the `sync' function. */ #undef HAVE_SYNC /* Define to 1 if you have the `sysconf' function. */ #undef HAVE_SYSCONF /* Define to 1 if you have the header file. */ #undef HAVE_SYS_DISKLABEL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MMAN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MOUNT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STATVFS_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_WAIT_H /* Define to 1 if you have the header file. */ #undef HAVE_TERMIOS_H /* Define to 1 if you have the `time' function. */ #undef HAVE_TIME /* Define to 1 if you have the header file. */ #undef HAVE_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_TR1_UNORDERED_MAP /* Define to 1 if you have the `tzset' function. */ #undef HAVE_TZSET /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the header file. */ #undef HAVE_UNORDERED_MAP /* Define to 1 if the system has the type `unsigned long long'. */ #undef HAVE_UNSIGNED_LONG_LONG /* Define to 1 if you have the `utimensat' function. */ #undef HAVE_UTIMENSAT /* Define to 1 if you have the `utimes' function. */ #undef HAVE_UTIMES /* Define to 1 if you have the header file. */ #undef HAVE_UTIME_H /* Define to 1 if you have the `vfork' function. */ #undef HAVE_VFORK /* Define to 1 if you have the header file. */ #undef HAVE_VFORK_H /* Define to 1 if you have the `waitpid' function. */ #undef HAVE_WAITPID /* Define to 1 if `fork' works. */ #undef HAVE_WORKING_FORK /* Define to 1 if `vfork' works. */ #undef HAVE_WORKING_VFORK /* Define to 1 if you have the header file. */ #undef HAVE_ZLIB_H /* Define to 1 if `lstat' dereferences a symlink specified with a trailing slash. */ #undef LSTAT_FOLLOWS_SLASHED_SYMLINK /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION /* Define for Solaris 2.5.1 so the uint32_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT32_T /* Define for Solaris 2.5.1 so the uint64_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT64_T /* Define for Solaris 2.5.1 so the uint8_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT8_T /* Define to the type of a signed integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef int32_t /* Define to rpl_malloc if the replacement function should be used. */ #undef malloc /* Define to `int' if does not define. */ #undef mode_t /* Define to `long int' if does not define. */ #undef off_t /* Define to `int' if does not define. */ #undef pid_t /* Define to `unsigned int' if does not define. */ #undef size_t /* Define to `int' if does not define. */ #undef ssize_t /* Define to the type of an unsigned integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ #undef uint16_t /* Define to the type of an unsigned integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef uint32_t /* Define to the type of an unsigned integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef uint64_t /* Define to the type of an unsigned integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ #undef uint8_t /* Define as `fork' if `vfork' does not work. */ #undef vfork fstransform-0.9.4/fsremap/src/copy.cc000066400000000000000000000036711345021500300175750ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * inode_cache.hh * * Created on: Aug 18, 2011 * Author: max */ #include "first.hh" #include "copy.hh" #if defined(FT_HAVE_STDIO_H) # include /* for snprintf() */ #elif defined(FT_HAVE_CSTDIO) && defined(__cplusplus) # include /* for snprintf() */ #endif FT_NAMESPACE_BEGIN void ff_set(ft_string & dst, const ft_string & src) { dst = src; } void ff_set(ft_string & dst, ft_ull src) { enum { maxlen = sizeof(ft_ull) * 3 + 1 }; dst.resize(maxlen); char * buf = &dst[0]; int delta = snprintf(buf, maxlen, "%" FT_XLL, src); dst.resize(delta > 0 ? delta : 0); } void ff_set(ft_ull & dst, const ft_string & src) { dst = 0; sscanf(src.c_str(), "%" FT_XLL, &dst); } void ff_cat(ft_string & dst, const ft_string & src) { dst += src; } void ff_cat(ft_string & dst, ft_ull src) { enum { maxlen = sizeof(ft_ull) * 3 + 1 }; size_t oldlen = dst.length(); dst.resize(oldlen + maxlen); char * buf = &dst[oldlen]; int delta = snprintf(buf, maxlen, "%" FT_XLL, src); dst.resize(oldlen + (delta > 0 ? delta : 0)); } FT_NAMESPACE_END fstransform-0.9.4/fsremap/src/copy.hh000066400000000000000000000025461345021500300176070ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * inode_cache.hh * * Created on: Aug 18, 2011 * Author: max */ #ifndef FSTRANSFORM_COPY_HH #define FSTRANSFORM_COPY_HH #include "types.hh" // for ft_string FT_NAMESPACE_BEGIN void ff_set(ft_string & dst, const ft_string & src); void ff_set(ft_string & dst, ft_ull src); void ff_set(ft_ull & dst, const ft_string & src); void ff_cat(ft_string & dst, const ft_string & src); void ff_cat(ft_string & dst, ft_ull src); FT_NAMESPACE_END #endif /* FSTRANSFORM_COPY_HH */ fstransform-0.9.4/fsremap/src/dispatch.cc000066400000000000000000000040361345021500300204160ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * dispatch.cc * * Created on: Mar 3, 2011 * Author: max */ #include "first.hh" #include "dispatch.hh" // for fr_dispatch #include "work.hh" // for fr_work FT_NAMESPACE_BEGIN /** * instantiate and run fr_work * with the smallest T that can represent device blocks count. * return 0 if success, else error. * * implementation: iterates on all known configured T and, * if both fr_work::check() and fr_work::init() succeed, * calls fr_work::run(), then fr_work::cleanup() */ int fr_dispatch::main(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents, FT_IO_NS fr_io & io) { if (fr_work::check(io) == 0) { ff_log(FC_INFO, 0, "using reduced (%" FT_ULL " bit) remapping algorithm", (ft_ull)8*sizeof(ft_uint)); return fr_work::main(loop_file_extents, free_space_extents, to_zero_extents, io); } ff_log(FC_INFO, 0, "using full (%" FT_ULL " bit) remapping algorithm", (ft_ull)8*sizeof(ft_uoff)); return fr_work::main(loop_file_extents, free_space_extents, to_zero_extents, io); } FT_NAMESPACE_END fstransform-0.9.4/fsremap/src/dispatch.hh000066400000000000000000000034411345021500300204270ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * dispatch.hh * * Created on: Mar 3, 2011 * Author: max */ #ifndef FSREMAP_WORK_BASE_HH #define FSREMAP_WORK_BASE_HH #include "types.hh" // for ft_uoff #include "fwd.hh" // for fr_io, fr_vector forward declarations FT_NAMESPACE_BEGIN class fr_dispatch { public: /** * instantiate and run fr_work::main(...) * with the smallest T that can represent device blocks count. * return 0 if success, else error. * * implementation: iterates on all configured T and, * if both fr_work::check(..) and fr_work::init(..) succeed, * calls ff_work::run(), then ff_work::cleanup() */ static int main(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents, FT_IO_NS fr_io & io); }; FT_NAMESPACE_END #endif /* FSREMAP_WORK_BASE_HH */ fstransform-0.9.4/fsremap/src/eta.cc000066400000000000000000000076561345021500300174030ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * eta.cc * * Created on: Mar 22, 2011 * Author: max */ #include "first.hh" #if defined(FT_HAVE_ERRNO_H) # include // for errno, EDOM #elif defined(FT_HAVE_CERRNO) # include // for errno, EDOM #endif #if defined(FT_HAVE_TIME_H) # include // for time_t, time() #elif defined(FT_HAVE_CTIME) # include // for time_t, time() #endif #include "eta.hh" // for ft_eta #include "misc.hh" // for ft_now FT_NAMESPACE_BEGIN static int ff_least_squares(ft_size N, const double xi[], const double yi[], double & ret_m, double & ret_q); /** default constructor */ ft_eta::ft_eta(ft_size max_n) : this_x(), this_y() { clear(max_n); } void ft_eta::clear(ft_size max_n) { this_x.clear(); this_y.clear(); this_max_n = max_n; } /** * add percentage and {current timestamp} to the sliding E.T.A. extrapolation. * return number of seconds to E.T.A., or < 0 if not enough data available yet. */ double ft_eta::add(double y) { enum { FC_ETA_MIN_N = 3 }; double x = 0.0; if (this_max_n == 0 || ff_now(x) != 0) return -1.0; /* also in case of error in gettimeofday */ /* slide window */ ft_size n = this_x.size(); if (n < this_max_n) n++; else { this_x.erase(this_x.begin()); this_y.erase(this_y.begin()); } this_x.push_back(x); this_y.push_back(y); if (n < this_max_n && n < FC_ETA_MIN_N) return -1.0; /* not enough data available yet */ /* * use the simple linear regression (least squares) * formula to find the line best-fitting all points */ double m_all = 0.0, q_all, m_last = 0.0, q_last, m; int err = ff_least_squares(n, & this_x[0], & this_y[0], m_all, q_all); if (err != 0 || m_all <= 0.0) return -1.0; /* ill-conditioned data */ /* repeat to find the line best-fitting last FC_ETA_MIN_N points */ err = ff_least_squares(FC_ETA_MIN_N, & this_x[0], & this_y[0], m_last, q_last); if (err == 0 && m_last > 0.0) /* make a brutal average between the two computed m */ m = 0.5 * (m_all + m_last); else m = m_all; /* but then cheat and change q to force the best-fitting line to pass from last point */ double x_left = (1.0 - y) / m; if (x_left < 0.0) return -1.0; /* E.T.A. is in the past! */ return x_left; } static int ff_least_squares(ft_size N, const double x[], const double y[], double & ret_m, double & ret_q) { double X = 0, X2 = 0; /* X = sum(x[i]), X2 = sum(x[i]^2) */ double Y = 0, Y2 = 0; /* Y = sum(y[i]), Y2 = sum(y[i]^2) */ double XY = 0; /* XY = sum(x[i]*y[i]) */ double x0 = x[0], y0 = y[0], x_, y_; for (ft_size i = 0; i < N; i++) { x_ = x[i] - x0; y_ = y[i] - y0; X += x_; X2 += x_ * x_; Y += y_; Y2 += y_ * y_; XY += x_ * y_; } double v = X2 - X*X/N; if (v == 0.0) return -EDOM; double c = XY - X*Y/N; ret_m = c / v; /* adjust back for x0, y0 */ ret_q = (Y - ret_m*X) / N + (y0 - ret_m*x0); return 0; } FT_NAMESPACE_END fstransform-0.9.4/fsremap/src/eta.hh000066400000000000000000000034011345021500300173750ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * eta.hh * * Created on: Mar 22, 2011 * Author: max */ #ifndef FSTRANSFORM_ETA_HH #define FSTRANSFORM_ETA_HH #include "types.hh" // for ft_size #include // for std::vector FT_NAMESPACE_BEGIN /** estimates time-of-arrival from a sliding window extrapolation of last 3 progress percentages */ class ft_eta { private: std::vector this_x; std::vector this_y; ft_size this_max_n; public: enum { DEFAULT_MAX_N = 12 }; ft_eta(ft_size max_n = DEFAULT_MAX_N); /** * add percentage and {current timestamp} to the sliding window E.T.A. extrapolation. * return number of seconds to E.T.A., or < 0 if not enough data available yet. */ double add(double percentage); /* reset this E.T.A. to empty */ void clear(ft_size max_n = DEFAULT_MAX_N); }; FT_NAMESPACE_END #endif /* FSTRANSFORM_ETA_HH */ fstransform-0.9.4/fsremap/src/extent.hh000066400000000000000000000205721345021500300201430ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * extent.hh * * Created on: Feb 27, 2011 * Author: max */ #ifndef FSREMAP_EXTENT_HH #define FSREMAP_EXTENT_HH #include "types.hh" // for ft_size #include "log.hh" // for ff_log() #include // for std_pair FT_NAMESPACE_BEGIN /** possible sources ('from') of a fr_work::move*() or io::fr_io::copy() operation */ enum fr_from { FC_FROM_DEV = 0, FC_FROM_STORAGE = 1 }; /** possible destinations ('to') of a fr_work::move*() or io::fr_io::copy() operation */ enum fr_to { FC_TO_DEV = 0, FC_TO_STORAGE = 2 }; /** direction of fr_work::move*() and io::fr_io::copy() operations */ enum fr_dir { FC_DEV2DEV = FC_FROM_DEV |FC_TO_DEV, FC_STORAGE2DEV = FC_FROM_STORAGE|FC_TO_DEV, FC_DEV2STORAGE = FC_FROM_DEV |FC_TO_STORAGE, FC_INVALID2INVALID = FC_FROM_STORAGE|FC_TO_STORAGE, /* 'invalid dir' marker */ }; FT_INLINE fr_from ff_from(fr_dir dir) { return (fr_from)(dir & 1); } FT_INLINE fr_to ff_to (fr_dir dir) { return (fr_to) (dir & 2); } FT_INLINE bool ff_is_from_dev(fr_dir dir) { return ff_from(dir) == FC_FROM_DEV; } FT_INLINE bool ff_is_to_dev (fr_dir dir) { return ff_to (dir) == FC_TO_DEV; } /** * ft_match enumerates the kinds of matches/intersections between extents or maps: * FC_PHYSICAL1: match/intersection of extents ->physical ranges. select subrange of extent1 -> logical * FC_PHYSICAL2: match/intersection of extents ->physical ranges. select subrange of extent2 -> logical * FC_BOTH: simultaneous match/intersection of extents ->physical and ->logical ranges */ enum ft_match { FC_BOTH = 0, FC_PHYSICAL1 = 1, FC_PHYSICAL2 = -1, }; /** swap FC_PHYSICAL1 <-> FC_PHYSICAL2 and FC_LOGICAL1 <-> FC_LOGICAL2 */ FT_INLINE ft_match ff_match_transpose(ft_match match) { return (ft_match)-match; } template struct fr_extent_key { mutable T physical; /* physical offset in bytes for the start of the extent from the beginning of the device */ }; // compare two fr_extent_key:s. needed by fr_map to order the keys! template FT_INLINE bool operator<(const fr_extent_key & key1, const fr_extent_key & key2) { return key1.physical < key2.physical; } template struct fr_extent_payload { T logical; /**< logical offset in bytes for the start of the extent from the beginning of the file */ T length; /**< length in bytes for this extent */ ft_size user_data; /**< caller can store its own data here. used to track whether this extents contains LOOP-FILE blocks or DEVICE blocks */ }; enum { FC_DEFAULT_USER_DATA = 0, /**< stored into fr_extent_payload::user_data when caller cannot supply a value */ FC_EXTENT_ZEROED = 1, /**< stored into fr_extent_payload::user_data to indicate that on-disk extent only contains zeroes */ }; template class fr_extent : public std::pair, fr_extent_payload > { private: typedef fr_extent_key key_type; typedef fr_extent_payload mapped_type; public: typedef std::pair super_type; /* default constructor */ fr_extent() : super_type() { } /* copy constructor */ fr_extent(const fr_extent & other) : super_type(other) { } /* copy constructor accepting base class */ fr_extent(const super_type & other) : super_type(other) { } /* assignment operator */ const super_type & operator=(const fr_extent & other) { super_type::operator=(other); return *this; } /* assignment operator accepting base class */ const super_type & operator=(const super_type & other) { super_type::operator=(other); return *this; } FT_INLINE T & physical() { return this->first.physical; } FT_INLINE T & logical() { return this->second.logical; } FT_INLINE T & length() { return this->second.length; } FT_INLINE T physical() const { return this->first.physical; } FT_INLINE T logical() const { return this->second.logical; } FT_INLINE T length() const { return this->second.length; } FT_INLINE ft_size & user_data() { return this->second.user_data; } FT_INLINE ft_size user_data() const { return this->second.user_data; } void clear() { physical() = logical() = length() = 0; user_data() = 0; } /** print extents header to log */ static void show(ft_log_level level = FC_SHOW_DEFAULT_LEVEL) { ff_log(level, 0, "# extent physical logical length user_data"); } /** print extent to log */ static void show(ft_size i, T physical, T logical, T length, ft_size user_data, ft_log_level level = FC_SHOW_DEFAULT_LEVEL) { ff_log(level, 0, "#%8" FT_ULL "\t%12" FT_ULL "\t%12" FT_ULL "\t%8" FT_ULL "\t(%" FT_ULL ")", (ft_ull)i, (ft_ull) physical, (ft_ull) logical, (ft_ull) length, (ft_ull) user_data); } /** print extent to log */ static void show(ft_size i, const super_type & extent, ft_log_level level = FC_SHOW_DEFAULT_LEVEL) { show(i, extent.first.physical, extent.second.logical, extent.second.length, extent.second.user_data, level); } template static void show(const_iter start, const_iter end, ft_size n, const char * label1, const char * label2, ft_uoff effective_block_size, ft_log_level level) { ft_log_level header_level = level >= FC_DEBUG ? level : (ft_log_level)(level + 1); if (!ff_log_is_enabled(header_level) && !ff_log_is_enabled(level)) return; if (start != end) { ff_log(header_level, 0, "# %4" FT_ULL " extent%s in %s%s", (ft_ull) n, (n == 1 ? "" : "s"), label1, label2); if (ff_log_is_enabled(level)) { ff_log(level, 0, "# effective block size = %" FT_ULL, (ft_ull) effective_block_size); show(level); for (ft_size i = 0; start != end; ++start, ++i) show(i, *start, level); } } else { ff_log(header_level, 0, "# no extents in %s%s", label1, label2); } ff_log(level, 0, ""); } class comparator_physical { public: FT_INLINE bool operator()(const fr_extent & e1, const fr_extent & e2) { return e1.physical() < e2.physical(); } }; class comparator_logical { public: FT_INLINE bool operator()(const fr_extent & e1, const fr_extent & e2) { return e1.logical() < e2.logical(); } }; class reverse_comparator_length { public: FT_INLINE bool operator()(const fr_extent & e1, const fr_extent & e2) { return e1.length() > e2.length(); } }; }; enum fr_extent_relation { FC_EXTENT_BEFORE, /**< first extent is before second, either they do not touch or they touch but their logical or user_data do not match */ FC_EXTENT_TOUCH_BEFORE,/**< first extent is before second, they touch exactly and their logical and user_data match too (so they can be merged) */ FC_EXTENT_INTERSECT, /**< first and second extent intersect each other by at least one (physical) byte */ FC_EXTENT_TOUCH_AFTER, /**< first extent is after second, they touch exactly and their logical and user_data match too (so they can be merged) */ FC_EXTENT_AFTER, /**< first extent is after second, either they do not touch or they touch but their logical or user_data do not match */ }; FT_NAMESPACE_END #endif /* FSREMAP_EXTENT_HH */ fstransform-0.9.4/fsremap/src/features.hh000066400000000000000000000061331345021500300204470ustar00rootroot00000000000000/* * common header for fsattr, fsmove, fsremap * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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, see . * * features.hh * * Created on: Feb 27, 2011 * Author: max */ #ifndef FSTRANSFORM_FEATURES_HH #define FSTRANSFORM_FEATURES_HH #ifdef FT_HAVE_EXTERN_C /** in C++, define to extern "C" { ... }. in C, define as empty */ # define FT_EXTERN_C_BEGIN extern "C" { # define FT_EXTERN_C_END } #else # define FT_EXTERN_C_BEGIN # define FT_EXTERN_C_END #endif /* FT_HAVE_EXTERN_C */ /* suppress warning about unused function argument */ #ifndef FT_ARG_UNUSED # define FT_ARG_UNUSED(arg) #endif #ifdef FT_HAVE_NAMESPACE /** in C++, define to namespace ft { ... }. in C, define as empty */ # define FT_NAMESPACE_BEGIN namespace ft { # define FT_NAMESPACE_END } # define FT_ARCH_NAMESPACE_BEGIN FT_NAMESPACE_BEGIN namespace arch { # define FT_ARCH_NAMESPACE_END } FT_NAMESPACE_END # define FT_IO_NAMESPACE_BEGIN FT_NAMESPACE_BEGIN namespace io { # define FT_IO_NAMESPACE_END } FT_NAMESPACE_END # define FT_UI_NAMESPACE_BEGIN FT_NAMESPACE_BEGIN namespace ui { # define FT_UI_NAMESPACE_END } FT_NAMESPACE_END # define FT_NS ft:: # define FT_ARCH_NS FT_NS arch:: # define FT_IO_NS FT_NS io:: # define FT_UI_NS FT_NS ui:: #else # define FT_NAMESPACE_BEGIN # define FT_NAMESPACE_END # define FT_ARCH_NAMESPACE_BEGIN # define FT_ARCH_NAMESPACE_END # define FT_IO_NAMESPACE_BEGIN # define FT_IO_NAMESPACE_END # define FT_UI_NAMESPACE_BEGIN # define FT_UI_NAMESPACE_END # define FT_NS # define FT_ARCH_NS # define FT_IO_NS # define FT_UI_NS #endif /* FT_HAVE_NAMESPACE */ // list of types we want to instantiate fr_work with #define FT_TYPE_LIST(ft_prefix, ft_macro) \ ft_macro(ft_prefix, ft_uint) \ ft_macro(ft_prefix, ft_uoff) /* * does compiler supports * extern template class Foo; * extern template int foo(T bar); * and * template class Foo; * template int foo(T bar); * to explicitly control template instantiation? */ #ifdef FT_HAVE_EXTERN_TEMPLATE # define FT_TEMPLATE_DECLARE(ft_macro) FT_TYPE_LIST(extern template, ft_macro) # define FT_TEMPLATE_INSTANTIATE(ft_macro) FT_TYPE_LIST( template, ft_macro) #else /* !defined(FT_HAVE_EXTERN_TEMPLATE) */ # define FT_TEMPLATE_DECLARE(ft_macro) # define FT_TEMPLATE_INSTANTIATE(ft_macro) #endif /* FT_HAVE_EXTERN_TEMPLATE */ #endif /* FSTRANSFORM_FEATURES_HH */ fstransform-0.9.4/fsremap/src/first.hh000066400000000000000000000032771345021500300177660ustar00rootroot00000000000000/* * common header for fsattr, fsmove, fsremap * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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, see . * * first.hh * * Created on: Feb 24, 2011 * Author: max */ #ifndef FSTRANSFORM_FIRST_HH #define FSTRANSFORM_FIRST_HH #if defined(__USE_ANSI) || defined(_FEATURES_H) || defined(FSTRANSFORM_FEATURES_HH) || defined(FSTRANSFORM_AUTOCONF_HH) # error "first.hh" must be included before any other #include #endif /* put here any option/define/... affecting system-wide includes */ /* * _GNU_SOURCE implies _LARGEFILE_SOURCE. * together with _FILE_OFFSET_BITS=64 they should set off_t to be at least 64 bits wide */ #ifndef _GNU_SOURCE # define _GNU_SOURCE #endif #ifndef _LARGEFILE_SOURCE # define _LARGEFILE_SOURCE #endif #ifndef _FILE_OFFSET_BITS # define _FILE_OFFSET_BITS 64 #endif /* put here any option/define/... affecting the whole program (headers and source files) */ #include "autoconf.hh" #ifdef FT_HAVE_FEATURES_H # include #endif #include "features.hh" #endif /* FSTRANSFORM_FIRST_HH */ fstransform-0.9.4/fsremap/src/fwd.hh000066400000000000000000000032041345021500300174050ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * fwd.hh * * Created on: Feb 27, 2011 * Author: max */ #ifndef FSREMAP_FWD_HH #define FSREMAP_FWD_HH #include "check.hh" FT_NAMESPACE_BEGIN class fr_args; class fr_remap; class fr_dispatch; class fr_job; template struct fr_extent_key; template struct fr_extent_payload; template class fr_extent; template class fr_vector; template class fr_map; template class fr_pool_entry; template class fr_pool; template class fr_work; FT_NAMESPACE_END FT_IO_NAMESPACE_BEGIN class fr_io; class fr_io_posix; class fr_io_test; class fr_io_self_test; FT_IO_NAMESPACE_END FT_UI_NAMESPACE_BEGIN class fr_ui; class fr_ui_tty; FT_UI_NAMESPACE_END #endif /* FSREMAP_FWD_HH */ fstransform-0.9.4/fsremap/src/io/000077500000000000000000000000001345021500300167145ustar00rootroot00000000000000fstransform-0.9.4/fsremap/src/io/extent_file.cc000066400000000000000000000107411345021500300215340ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/extent_file.cc * * Created on: Mar 3, 2011 * Author: max */ #include "../first.hh" #if defined(FT_HAVE_ERRNO_H) # include // for errno, ENOMEM, EINVAL, EFBIG #elif defined(FT_HAVE_CERRNO) # include // for errno, ENOMEM, EINVAL, EFBIG #endif #include "../types.hh" // for ft_off #include "../extent.hh" // for fr_extent #include "../vector.hh" // for fr_vector #include "extent_file.hh" // for ff_read_extents_file() FT_IO_NAMESPACE_BEGIN /** * load file blocks allocation map (extents) previously saved into specified file * and appends them to ret_container (retrieves also user_data) * in case of failure returns errno-compatible error code, and ret_list contents will be UNDEFINED. * * implementation: simply reads the list of triplets (physical, logical, length) * stored in the stream as decimal numbers */ int ff_load_extents_file(FILE * f, fr_vector & ret_list, ft_uoff & ret_block_size_bitmask) { { char header[200]; for (ft_size i = 0; i < 6; i++) { if (fgets(header, sizeof(header), f) == NULL || header[0] != '#') return EPROTO; } } ft_ull physical, logical, length = 0, user_data; if (fscanf(f, "count %" FT_ULL "\n", & length) != 1) return EPROTO; if (fscanf(f, "physical\tlogical\tlength\tuser_data\n") < 0) return EPROTO; ft_uoff block_size_bitmask = ret_block_size_bitmask; ft_size i = ret_list.size(), n = (ft_size) length; ret_list.resize(n += i); for (; i < n; i++) { if (fscanf(f, "%" FT_ULL " %" FT_ULL " %" FT_ULL " %" FT_ULL "\n", &physical, &logical, &length, &user_data) != 4) return EPROTO; fr_extent & extent = ret_list[i]; block_size_bitmask |= (extent.physical() = (ft_uoff) physical) | (extent.logical() = (ft_uoff) logical) | (extent.length() = (ft_uoff) length); extent.user_data() = (ft_size) user_data; } ret_block_size_bitmask = block_size_bitmask; return 0; } /** * writes file blocks allocation map (extents) to specified FILE (stores also user_data) * in case of failure returns errno-compatible error code. * * implementation: simply writes the list of triplets (physical, logical, length) * into the FILE as decimal numbers */ int ff_save_extents_file(FILE * f, const fr_vector & extent_list) { fprintf(f, "%s", "################################################################################\n" "###################### DO NOT EDIT THIS FILE ! ################################\n" "################################################################################\n" "############# This file was automatically generated by fsremap. ############\n" "############# Any change you may do will CORRUPT resuming this job! ############\n" "################################################################################\n"); fprintf(f, "count %" FT_ULL "\n", (ft_ull) extent_list.size()); fprintf(f, "physical\tlogical\tlength\tuser_data\n"); fr_vector::const_iterator iter = extent_list.begin(), end = extent_list.end(); for (; iter != end; ++iter) { const fr_extent & extent = *iter; if (fprintf(f, "%" FT_ULL "\t%" FT_ULL "\t%" FT_ULL "\t%" FT_ULL "\n", (ft_ull)extent.physical(), (ft_ull)extent.logical(), (ft_ull)extent.length(), (ft_ull)extent.user_data()) <= 0) break; } return iter == end ? 0 : errno; } FT_IO_NAMESPACE_END fstransform-0.9.4/fsremap/src/io/extent_file.hh000066400000000000000000000045611345021500300215510ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/extent_posix.hh * * Created on: Feb 27, 2011 * Author: max */ #ifndef FSREMAP_IO_POSIX_EXTENT_HH #define FSREMAP_IO_POSIX_EXTENT_HH #include "../check.hh" #if defined(FT_HAVE_STDIO_H) # include // for FILE #elif defined(FT_HAVE_CSTDIO) # include // for FILE #endif #include "../fwd.hh" // for fr_vector forward declaration */ #include "../types.hh" // for ft_uoff FT_IO_NAMESPACE_BEGIN /** * load file blocks allocation map (extents) previously saved into specified file * and appends them to ret_container (retrieves also user_data) * in case of failure returns errno-compatible error code, and ret_list contents will be UNDEFINED. * * implementation: simply reads the list of triplets (physical, logical, length) * stored in the stream as decimal numbers */ int ff_load_extents_file(FILE * f, fr_vector & ret_list, ft_uoff & ret_block_size_bitmask); /** * writes file blocks allocation map (extents) to specified FILE (stores also user_data) * in case of failure returns errno-compatible error code. * * implementation: simply writes the list of triplets (physical, logical, length) * into the FILE as decimal numbers */ int ff_save_extents_file(FILE * f, const fr_vector & extent_list); /** * write 'length' bytes of zeros '\0' into file descriptor and return 0. * in case of failure returns errno-compatible error code. */ int ff_write_zero_fd(int fd, ft_uoff length); FT_IO_NAMESPACE_END #endif /* FSREMAP_FILEMAP_HH */ fstransform-0.9.4/fsremap/src/io/extent_posix.cc000066400000000000000000000325641345021500300217660ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/extent_posix.cc * * Created on: Feb 27, 2011 * Author: max */ #include "../first.hh" // for FT_*TEMPLATE* macros */ #if defined(FT_HAVE_ERRNO_H) # include // for errno, ENOMEM, EINVAL, EFBIG #elif defined(FT_HAVE_CERRNO) # include // for errno, ENOMEM, EINVAL, EFBIG #endif #if defined(FT_HAVE_STDLIB_H) # include // for malloc(), free() #elif defined(FT_HAVE_CSTDLIB) # include // for malloc(), free() #endif #if defined(FT_HAVE_STRING_H) # include // for memset() #elif defined(FT_HAVE_CSTRING) # include // for memset() #endif #ifdef FT_HAVE_SYS_IOCTL_H # include // for ioctl() #endif #ifdef FT_HAVE_LINUX_FS_H # include // for FS_IOC_FIEMAP, FIBMAP */ #endif #ifdef FT_HAVE_LINUX_FIEMAP_H /* if defines FS_IOC_FIEMAP, is supposed to exist */ # include // for struct fiemap and struct fiemap_extent. #endif #include // for std::pair and std::make_pair() #include // for std::vector #include "../log.hh" // for ff_log() */ #include "../traits.hh" // for FT_TYPE_TO_UNSIGNED(T) */ #include "../types.hh" // for ft_off */ #include "../extent.hh" // for fr_extent, fr_map, ff_filemap() */ #include "../vector.hh" // for fr_vector */ #include "extent_posix.hh" // for ff_read_extents_posix() */ #include "util_posix.hh" // for ff_posix_ioctl(), ff_posix_size() */ FT_IO_NAMESPACE_BEGIN /** * retrieves file blocks allocation map (extents) for specified file descriptor * and appends them to ret_vector (with user_data = FC_DEFAULT_USER_DATA). * in case of failure returns errno-compatible error code, and ret_vector contents will be UNDEFINED. * * must (and will) also check that device size can be represented by ret_list, * * implementation: calls ioctl(FIBMAP) */ static int ff_posix_fibmap(int fd, ft_uoff dev_length, fr_vector & ret_list, ft_uoff & ret_block_size_bitmask) { #ifdef FIBMAP ft_uoff file_length, file_block_count, dev_block_count; ft_uoff ioctl_n = 0, block_size = 0, logical_uoff, physical_uoff; ft_size extent_n = ret_list.size(); /* lower-level API ff_posix_ioctl(FIGETBSZ) and ff_posix_ioctl(FIBMAP) need these to be int */ int err = 0, block_size_int, logical, physical; do { if ((err = ff_posix_ioctl(fd, FIGETBSZ, & block_size_int))) { err = ff_log(FC_ERROR, err, "ff_posix_fibmap(): error in ioctl(%d, FIGETBSZ)", fd); break; } block_size = (ft_uoff) block_size_int; // ft_uoff is expected to be wider than int, // but explicitly checking for overflow is always safer than "expecting" if ((int) block_size != block_size_int) { /* overflow! give up. */ err = ff_log(FC_ERROR, EFBIG, "ff_posix_fibmap(): error, block_size = %" FT_ULL " overflows type (ft_uoff)", (ft_ull) block_size_int); break; } if ((err = ff_posix_size(fd, & file_length))) { err = ff_log(FC_ERROR, err, "ff_posix_fibmap(): error in stat(%d)", fd); break; } // number of blocks in the device dev_block_count = (dev_length + block_size - 1) / block_size; // number of blocks in the file file_block_count = (file_length + block_size - 1) / block_size; // ioctl(FIBMAP) wants an (int logical) and returns an (int physical) // in units of one block, so we must check for overflow! int n = (int) file_block_count; int m = (int) dev_block_count; if (m < 0 || dev_block_count != (ft_uoff) m || n < 0 || file_block_count != (ft_uoff) n) { /* overflow! give up. */ err = ff_log(FC_ERROR, EFBIG, "ff_posix_fibmap(): error, dev_block_count = %" FT_ULL ", file_block_count = %" FT_ULL " overflow type (int)", (ft_ull) dev_block_count, (ft_ull) file_block_count); break; } for (logical = 0; logical < n; logical++) { physical = logical; ioctl_n++; if ((err = ff_posix_ioctl(fd, FIBMAP, & physical))) { err = ff_log(FC_ERROR, err, "ff_posix_fibmap(): error in ioctl(%d, FIBMAP, %" FT_ULL ")", fd, (ft_ull) logical); break; } /* FIBMAP reports holes (i.e. unallocated blocks in the file) as physical == 0. ugly */ if (physical != 0) { physical_uoff = (ft_uoff) physical * block_size; logical_uoff = (ft_uoff) logical * block_size; /* this is painful... FIBMAP reports one block per call */ ret_list.append(physical_uoff, logical_uoff, block_size, FC_DEFAULT_USER_DATA); } } } while (0); if (err == 0) { static ft_ull log_count = 0; if (log_count++ == 5) ff_log(FC_DEBUG, 0, "decreasing to level TRACE any further DEBUG message 'ioctl(FIBMAP) successful'"); extent_n = ret_list.size() - extent_n; ff_log(log_count < 5 ? FC_DEBUG : FC_TRACE, 0, "ioctl(%d, FIBMAP) successful: retrieved %" FT_ULL " extent%s in %" FT_ULL " call%s", fd, (ft_ull) extent_n, extent_n == 1 ? "" : "s", (ft_ull) ioctl_n, ioctl_n == 1 ? "" : "s"); /* keep track of bits used by extents. needed to compute effective block size */ ret_block_size_bitmask |= block_size; } return err; #else return ENOSYS; #endif /* FIBMAP */ } #ifdef FS_IOC_FIEMAP static int ff_linux_fiemap(int fd, ft_uoff file_start, ft_uoff file_end, ft_u32 extent_n, struct fiemap * k_map) { ft_size k_len = sizeof(struct fiemap) + extent_n * sizeof(struct fiemap_extent); memset(k_map, 0, k_len); k_map->fm_start = (ft_u64) file_start; k_map->fm_length = (ft_u64) (file_end - file_start); k_map->fm_flags = FIEMAP_FLAG_SYNC; k_map->fm_extent_count = extent_n; int err = 0; if ((err = ff_posix_ioctl(fd, FS_IOC_FIEMAP, k_map)) != 0) { static ft_ull log_count = 0; if (log_count++ == 5) ff_log(FC_DEBUG, 0, "decreasing to level TRACE any further DEBUG message 'ioctl(FIEMAP) failed'"); /* do not mark the error as reported, this is just a DEBUG message */ ff_log(log_count < 5 ? FC_DEBUG : FC_TRACE, 0, "ioctl(%d, FIEMAP, extents[%" FT_ULL "]) failed (%s), falling back on ioctl(FIBMAP) ...", fd, (ft_ull) extent_n, strerror(err)); } return err; } #endif /* FS_IOC_FIEMAP */ /* * retrieves file blocks allocation map (extents) for specified file descriptor * and appends them to ret_vector (with user_data = FC_DEFAULT_USER_DATA). * in case of failure returns errno-compatible error code and ret_vector contents will be UNCHANGED. * * must (and will) also check that device size can be represented by ret_list * * implementation: calls ioctl(FS_IOC_FIEMAP) */ static int ff_linux_fiemap(int fd, fr_vector & ret_list, ft_uoff & ret_block_size_bitmask) { #ifdef FS_IOC_FIEMAP ft_uoff file_start = 0, file_size; int err; if ((err = ff_posix_size(fd, & file_size)) || file_size == 0) return err; fr_vector tmp_list; enum { K_EXTENT_N = 1024, K_SIZEOF_FIEMAP = sizeof(struct fiemap) + K_EXTENT_N * sizeof(struct fiemap_extent) }; char buf[K_SIZEOF_FIEMAP]; struct fiemap * k_map = (struct fiemap *) buf; ft_uoff ioctl_n = 0, block_size_bitmask = ret_block_size_bitmask; // call ioctl() repeatedly until we retrieve all extents while (ioctl_n++, (err = ff_linux_fiemap(fd, file_start, file_size, K_EXTENT_N, k_map)) == 0) { ft_u32 i, extent_n = k_map->fm_mapped_extents; const struct fiemap_extent * extents = k_map->fm_extents; if (extent_n == 0) { /* we did not get any extent... bail out */ ff_log(FC_WARN, 0, "ioctl(%d, FS_IOC_FIEMAP) is refusing to return any extent after file offset = %" FT_ULL ", falling back on ioctl(FIBMAP) ...", fd, (ft_ull) file_start); /* mark the error as reported, WARN is quite a severe level */ err = -ENOSYS; /* ioctl(FS_IOC_FIEMAP) not working as expected... */ break; } const struct fiemap_extent & last_e = extents[extent_n - 1]; const ft_uoff new_file_start = (ft_uoff) last_e.fe_logical + (ft_uoff) last_e.fe_length; if (new_file_start <= file_start) { ff_log(FC_WARN, 0, "ioctl(%d, FS_IOC_FIEMAP) returned extents ending at %" FT_ULL ", i.e. _before_ start of requested range [%" FT_ULL ", %" FT_ULL "]" ", falling back on ioctl(FIBMAP) ...", fd, (ft_ull) new_file_start, (ft_ull) file_start, (ft_ull) file_size); /* mark the error as reported, WARN is quite a severe level */ err = -ENOSYS; /* ioctl(FS_IOC_FIEMAP) not working as expected... */ break; } tmp_list.reserve(tmp_list.size() + extent_n); for (i = 0; i < extent_n; i++) { const struct fiemap_extent & e = extents[i]; ft_u32 flag = e.fe_flags & (FIEMAP_EXTENT_UNKNOWN | FIEMAP_EXTENT_ENCODED); if (flag) { ff_log(FC_DEBUG, 0, "ioctl(%d, FS_IOC_FIEMAP, extents[%" FT_ULL "]) returned unsupported %s%s%s extents, falling back on ioctl(FIBMAP) ...", fd, (ft_ull) extent_n, (flag & FIEMAP_EXTENT_UNKNOWN ? "UNKNOWN" : ""), (flag == (FIEMAP_EXTENT_UNKNOWN|FIEMAP_EXTENT_ENCODED) ? "+" : ""), (flag & FIEMAP_EXTENT_ENCODED ? "ENCODED" : "") ); // do not mark the error as reported, this is just a DEBUG message err = ENOSYS; break; } /* * keep track of bits used by all physical, logical and lengths. * needed to check against block size */ block_size_bitmask |= e.fe_physical | e.fe_logical | e.fe_length; // save what we retrieved tmp_list.append((ft_uoff) e.fe_physical, (ft_uoff) e.fe_logical, (ft_uoff) e.fe_length, (e.fe_flags & FIEMAP_EXTENT_UNWRITTEN) ? FC_EXTENT_ZEROED : FC_DEFAULT_USER_DATA); } if (err != 0 || (last_e.fe_flags & FIEMAP_EXTENT_LAST)) break; // no FIEMAP_EXTENT_LAST found, we did not get all the extents. keep trying... if (new_file_start >= file_size) // should not happen, but not too dangerous file_size = new_file_start + 1; file_start = new_file_start; } if (err != 0) return err; ft_size extent_n = tmp_list.size(); /* ok, no strange extents: we can now add them to ret_list */ ret_list.reserve(ret_list.size() + extent_n); ret_list.append_all(tmp_list); static ft_ull log_count = 0; if (log_count++ == 5) ff_log(FC_DEBUG, 0, "decreasing to level TRACE any further DEBUG message 'ioctl(FIEMAP) successful'"); ff_log(log_count < 5 ? FC_DEBUG : FC_TRACE, 0, "ioctl(%d, FIEMAP) successful: retrieved %" FT_ULL " extent%s in %" FT_ULL " call%s", fd, (ft_ull) extent_n, extent_n == 1 ? "" : "s", (ft_ull) ioctl_n, ioctl_n == 1 ? "" : "s"); ret_block_size_bitmask = block_size_bitmask; return err; #else return ENOSYS; #endif /* FS_IOC_FIEMAP */ } /** * retrieves file blocks allocation map (extents) for specified file descriptor * and appends them to ret_vector (with user_data = FC_DEFAULT_USER_DATA) sorted by ->logical * in case of failure returns errno-compatible error code, and ret_vector contents will be UNDEFINED. * * implementation: calls ioctl(FS_IOC_FIEMAP) and if it fails, tries with ioctl(FIBMAP) */ int ff_read_extents_posix(int fd, ft_uoff dev_length, fr_vector & ret_list, ft_uoff & ret_block_size_bitmask) { int err; do { err = ff_linux_fiemap(fd, ret_list, ret_block_size_bitmask); if (err != 0) { int err2 = ff_posix_fibmap(fd, dev_length, ret_list, ret_block_size_bitmask); if (err2 != 0) { if (!ff_log_is_reported(err)) err = ff_log(FC_ERROR, err, "%s", "failed to list file blocks with ioctl(FS_IOC_FIEMAP)"); if (!ff_log_is_reported(err2)) err2 = ff_log(FC_ERROR, err2, "%s", "failed to list file blocks with ioctl(FIBMAP)"); } err = err2; } } while (0); return err; } FT_IO_NAMESPACE_END fstransform-0.9.4/fsremap/src/io/extent_posix.hh000066400000000000000000000032761345021500300217760ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/extent_posix.hh * * Created on: Feb 27, 2011 * Author: max */ #ifndef FSREMAP_IO_POSIX_EXTENT_HH #define FSREMAP_IO_POSIX_EXTENT_HH #include "../fwd.hh" // for fr_vector forward declaration */ #include "../types.hh" // for ft_uoff FT_IO_NAMESPACE_BEGIN /** * retrieves file blocks allocation map (extents) for specified file descriptor * and appends them to ret_vector (with user_data = FC_DEFAULT_USER_DATA) sorted by ->logical * in case of failure returns errno-compatible error code, and ret_vector contents will be UNDEFINED. * * implementation: calls ioctl(FS_IOC_FIEMAP) and if it fails, tries with ioctl(FIBMAP) */ int ff_read_extents_posix(int fd, ft_uoff dev_length, fr_vector & ret_list, ft_uoff & ret_block_size_bitmask); FT_IO_NAMESPACE_END #endif /* FSREMAP_FILEMAP_HH */ fstransform-0.9.4/fsremap/src/io/io.cc000066400000000000000000000254731345021500300176450ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/io.cc * * Created on: Mar 1, 2011 * Author: max */ #include "../first.hh" #if defined(FT_HAVE_STDIO_H) # include // for fopen(), fclose() #elif defined(FT_HAVE_CSTDIO) # include // for fopen(), fclose() #endif #include "../log.hh" // for ff_log() #include "../misc.hh" // for ff_can_sum() #include "../ui/ui.hh" // for fr_ui #include "io.hh" // for fr_io #include "extent_file.hh" // for ff_write_extents_file() FT_IO_NAMESPACE_BEGIN char const * const fr_io::label[] = { "device", "loop-file", "zero-file", "secondary-storage", "primary-storage", "storage", "free-space" }; char const * const fr_io::LABEL[] = { "DEVICE", "LOOP-FILE", "ZERO-FILE", "SECONDARY-STORAGE", "PRIMARY-STORAGE", "STORAGE", "FREE-SPACE" }; char const* const fr_io::extents_filename[FC_IO_EXTENTS_COUNT] = { "/loop_extents.txt", "/free_space_extents.txt", "/to_zero_extents.txt" }; /** constructor */ fr_io::fr_io(fr_persist & persist) : this_primary_storage(), request_vec(), this_dev_length(0), this_loop_file_length(0), this_eff_block_size_log2(0), this_dev_path(NULL), this_cmd_umount(NULL), this_job(persist.job()), this_persist(persist), this_ui(NULL), request_dir(FC_INVALID2INVALID), this_delegate_ui(false) { this_secondary_storage.clear(); } /** * destructor. * sub-classes must override it to call close() if they override close() */ fr_io::~fr_io() { } /** * open this fr_io. * sub-classes must override this method to perform appropriate initialization, * and the first thing sub-classes open() must do is to call fr_io::open(). */ int fr_io::open(const fr_args & args) { this_cmd_umount = args.cmd_umount; return 0; } /** * close this fr_io. * sub-classes must override this method to perform appropriate cleanup */ void fr_io::close() { this_primary_storage.clear(); this_secondary_storage.clear(); request_vec.clear(); request_dir = FC_INVALID2INVALID; this_dev_length = this_eff_block_size_log2 = 0; this_dev_path = NULL; } /** compute and return log2() of effective block size */ ft_uoff fr_io::effective_block_size_log2(ft_uoff block_size_bitmask) { ft_uoff block_size_log2 = 0; if (block_size_bitmask != 0) { while ((block_size_bitmask & 1) == 0) { block_size_log2++; block_size_bitmask >>= 1; } } return block_size_log2; } /* return (-)EOVERFLOW if request from/to + length overflow specified maximum value */ int fr_io::validate(const char * type_name, ft_uoff type_max, fr_dir dir, ft_uoff from, ft_uoff to, ft_uoff length) { to = ff_max2(from, to); if (!ff_can_sum(to, length) || length > type_max || to > type_max - length) { return ff_log(FC_FATAL, EOVERFLOW, "internal error! %s to %s io.copy(dir = %d, from_physical = %" FT_ULL ", to_physical = %" FT_ULL ", length = %" FT_ULL ")" " overflows maximum allowed (%s)%" FT_ULL , ff_is_from_dev(dir) ? label[FC_DEVICE] : label[FC_STORAGE], ff_is_to_dev(dir) ? label[FC_DEVICE] : label[FC_STORAGE], (int)dir, (ft_ull)from, (ft_ull)to, (ft_ull)length, type_name, (ft_ull)type_max); } return 0; } /** * if replaying an existing job, calls ff_load_extents_file() to load saved extents files. * otherwise calls the 4-argument version of read_extents() and, if it succeeds, * calls effective_block_size_log2() to compute and remember effective block size */ int fr_io::read_extents(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents) { ft_uoff block_size_bitmask = 0; int err; if (is_replaying()) err = load_extents(loop_file_extents, free_space_extents, to_zero_extents, block_size_bitmask); else err = read_extents(loop_file_extents, free_space_extents, to_zero_extents, block_size_bitmask); if (err == 0) { this_eff_block_size_log2 = effective_block_size_log2(block_size_bitmask); ff_log(FC_INFO, 0, "%s effective block size = %" FT_ULL , label[FC_DEVICE], (ft_ull) 1 << this_eff_block_size_log2); } return err; } /** * loads extents from files 'loop_extents.txt', 'free_space_extents.txt' and 'to_zero_extents.txt' * inside folder job.job_dir() by calling the function ff_load_extents_file() * if successful, calls effective_block_size_log2() to compute and remember effective block size */ int fr_io::load_extents(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents, ft_uoff & ret_block_size_bitmask) { fr_vector * ret_extents[] = { & loop_file_extents, & free_space_extents, & to_zero_extents }; ft_string path; ft_uoff block_size_bitmask = 0; const ft_string & job_dir = this_job.job_dir(); FILE * f = NULL; const char * path_cstr = NULL; int err = 0; for (ft_size i = 0; err == 0 && i < FC_IO_EXTENTS_COUNT; i++) { path = job_dir; path += extents_filename[i]; path_cstr = path.c_str(); if ((f = fopen(path_cstr, "r")) == NULL) { if (i == FC_IO_EXTENTS_TO_ZERO) ff_log(FC_WARN, errno, "this job is probably from version 0.9.3, cannot open persistence file '%s'", path_cstr); else err = ff_log(FC_ERROR, errno, "error opening persistence file '%s'", path_cstr); break; } if ((err = ff_load_extents_file(f, * ret_extents[i], block_size_bitmask)) != 0) err = ff_log(FC_ERROR, err, "error reading persistence file '%s'", path_cstr); if (fclose(f) != 0) { ff_log(FC_WARN, errno, "warning: failed to close persistence file '%s'", path_cstr); f = NULL; } } if (err == 0) ret_block_size_bitmask = block_size_bitmask; return err; } /** * saves extents to files job.job_dir() + '/loop_extents.txt' and job.job_dir() + '/free_space_extents.txt' * by calling the function ff_save_extents_file() */ int fr_io::save_extents(const fr_vector & loop_file_extents, const fr_vector & free_space_extents, const fr_vector & to_zero_extents) const { const fr_vector * extents[] = { & loop_file_extents, & free_space_extents, & to_zero_extents }; ft_string path; const ft_string & job_dir = this_job.job_dir(); FILE * f = NULL; const char * path_cstr = NULL; int err = 0; for (ft_size i = 0; err == 0 && i < FC_IO_EXTENTS_COUNT; i++) { path = job_dir; path += extents_filename[i]; path_cstr = path.c_str(); if ((f = fopen(path_cstr, "w")) == NULL) { err = ff_log(FC_ERROR, errno, "error opening persistence file '%s'", path_cstr); break; } if ((err = ff_save_extents_file(f, * extents[i])) != 0) err = ff_log(FC_ERROR, err, "error writing to persistence file '%s'", path_cstr); if (fclose(f) != 0) { ff_log(FC_WARN, errno, "error closing persistence file '%s'", path_cstr); f = NULL; } } return err; } /** * called once by work::relocate() immediately before starting the remapping phase. * * must be overridden by sub-classes to check that last device block to be written is actually writable. * Reason: at least on Linux, if a filesystems is smaller than its containing device, it often limits to its length the writable blocks in the device. * * default implementation: do nothing and return success (0) */ int fr_io::check_last_block() { return 0; } /** * perform buffering and coalescing of copy requests. * queues a copy of single fragment from DEVICE or FREE-STORAGE, to STORAGE to FREE-DEVICE. * calls flush_queue() as needed to actually perform any copy that cannot be buffered or coalesced. * note: parameters are in bytes! * return 0 if success, else error */ int fr_io::copy_bytes(fr_dir dir, ft_uoff from_physical, ft_uoff to_physical, ft_uoff length) { int err = 0; if (!request_vec.empty() && request_dir != dir) { if ((err = flush_queue()) != 0) return err; } if ((err = validate("ft_uoff", (ft_uoff)-1, dir, from_physical, to_physical, length)) != 0) return err; // do NOT actually show anything while replaying persistence if (this_ui != 0 && !this_delegate_ui && !is_replaying()) this_ui->show_io_copy(dir, from_physical, to_physical, length); request_dir = dir; request_vec.append(from_physical, to_physical, length, FC_DEFAULT_USER_DATA); return err; } /** * flush any pending copy, i.e. actually perform all queued copies. * return 0 if success, else error * on return, 'ret_copied' will be increased by the number of blocks actually copied (NOT queued for copying), * which could be > 0 even in case of errors */ int fr_io::flush_queue() { int err = 0; if (!request_vec.empty()) { // do NOT actually copy anything while replaying persistence if (!is_replaying()) err = flush_copy_bytes(request_dir, request_vec); request_vec.clear(); request_dir = FC_INVALID2INVALID; } return err; } /** * flush any I/O specific buffer * return 0 if success, else error * default implementation: do nothing */ int fr_io::flush_bytes() { return 0; } /** * flush any pending copy (call copy_bytes() through flush_queue()), * then flush any I/O specific buffer (call flush_bytes()). * Finall, call ui->show_io_flush() if needed * return 0 if success, else error */ int fr_io::flush() { int err = flush_queue(); // do NOT actually copy anything while replaying persistence if (!is_replaying()) { if (err == 0) err = flush_bytes(); if (err == 0 && this_ui != 0 && !this_delegate_ui) this_ui->show_io_flush(); } return err; } /** called to remove storage from file system if execution is successful */ int fr_io::remove_storage_after_success() { return 0; } FT_IO_NAMESPACE_END fstransform-0.9.4/fsremap/src/io/io.hh000066400000000000000000000377501345021500300176600ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/io.hh * * Created on: Mar 1, 2011 * Author: max */ #ifndef FSREMAP_IO_IO_HH #define FSREMAP_IO_IO_HH #include "../check.hh" #include "../types.hh" // for ft_uoff, ft_size, ft_string #include "../fwd.hh" // for fr_args forward declaration #include "../job.hh" // for fr_job #include "../extent.hh" // for fr_extent #include "../vector.hh" // for fr_vector #include "../map.hh" // for fr_map #include "../ui/ui.hh" // for fr_ui #include "persist.hh" // for ft_persist #include "request.hh" // for ft_request FT_IO_NAMESPACE_BEGIN /** * abstract base class for all I/O implementations * that actually read and write on DEVICE */ class fr_io { public: enum { FC_DEVICE = 0, FC_LOOP_FILE }; static char const * const label[]; // device, loop-file (and also others, but don't tell) static char const * const LABEL[]; // DEVICE, LOOP-FILE (and also others, but don't tell) enum { FC_IO_EXTENTS_LOOP, FC_IO_EXTENTS_FREE_SPACE, FC_IO_EXTENTS_TO_ZERO, FC_IO_EXTENTS_COUNT = 3, }; static char const* const extents_filename[FC_IO_EXTENTS_COUNT]; // "/loop_extents.txt", "/free_space_extents.txt", "/to_zero_extents.txt" private: fr_vector this_primary_storage; fr_extent this_secondary_storage; fr_vector request_vec; ft_uoff this_dev_length, this_loop_file_length, this_eff_block_size_log2; const char * this_dev_path; const char * this_cmd_umount; fr_job & this_job; fr_persist & this_persist; FT_UI_NS fr_ui * this_ui; fr_dir request_dir; bool this_delegate_ui; /* cannot call copy constructor */ fr_io(const fr_io &); /* cannot call assignment operator */ const fr_io & operator=(const fr_io &); protected: enum { FC_ZERO_FILE = FC_LOOP_FILE + 1, FC_SECONDARY_STORAGE, FC_PRIMARY_STORAGE, FC_STORAGE, FC_FREE_SPACE, }; /** remember device length */ FT_INLINE void dev_length(ft_uoff dev_length) { this_dev_length = dev_length; } /** remember loop file length */ FT_INLINE void loop_file_length(ft_uoff loop_file_length) { this_loop_file_length = loop_file_length; } /** remember device path */ FT_INLINE void dev_path(const char * dev_path) { this_dev_path = dev_path; } /** compute and return log2() of effective block size. */ static ft_uoff effective_block_size_log2(ft_uoff block_size_bitmask); /** return (-)EOVERFLOW if request from/to + length overflow specified maximum value */ static int validate(const char * type_name, ft_uoff type_max, fr_dir dir, ft_uoff from, ft_uoff to, ft_uoff length); /** return (-)EOVERFLOW if request from/to + length overflow specified maximum value */ FT_INLINE static int validate(const char * type_name, ft_uoff type_max, fr_dir dir, const fr_extent & extent) { return validate(type_name, type_max, dir, extent.physical(), extent.logical(), extent.length()); } /** invoked by derived classes to tell whether they will invoke ui methods by themselves (default: false) */ FT_INLINE void delegate_ui(bool flag_delegate_ui) { this_delegate_ui = flag_delegate_ui; } /** * retrieve LOOP-FILE extents, FREE-SPACE extents and any additional extents to be ZEROED * and insert them into the vectors loop_file_extents, free_space_extents and to_zero_extents * the vectors will be ordered by extent ->logical (for to_zero_extents, ->physical and ->logical will be the same). * * return 0 for success, else error (and vectors contents will be UNDEFINED). * * if success, also returns in ret_effective_block_size_log2 the log2() * of device effective block size. * the device effective block size is defined as follows: * it is the largest power of 2 that exactly divides all physical, * logical and lengths in all returned extents (both for LOOP-FILE * and for FREE-SPACE) and that also exactly exactly divides device length. * * must be overridden by sub-classes. * * a common trick subclasses may use to implement this method * is to fill the device's free space with a ZERO-FILE, * and actually retrieve the extents used by ZERO-FILE. */ virtual int read_extents(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents, ft_uoff & ret_effective_block_size_log2) = 0; /** * get writable reference to secondary_storage. * must be called by create_storage() to set the details of secondary_storage */ FT_INLINE fr_extent & secondary_storage() { return this_secondary_storage; } /** * flush any pending copy, i.e. actually call copy_bytes(request). * return 0 if success, else error * on return, 'ret_copied' will be increased by the number of blocks actually copied (NOT queued for copying), * which could be > 0 even in case of errors */ int flush_queue(); /** * actually copy a list of fragments from DEVICE or FREE-STORAGE, to STORAGE to FREE-DEVICE. * must be implemented by sub-classes. * note: parameters are in bytes! * return 0 if success, else error. */ virtual int flush_copy_bytes(fr_dir dir, fr_vector & request_vec) = 0; /** * flush any I/O specific buffer * return 0 if success, else error * default implementation: do nothing */ virtual int flush_bytes(); /** * write zeroes to device (or to storage). * used to remove device-renumbered blocks once remapping is finished */ virtual int zero_bytes(fr_to to, ft_uoff offset, ft_uoff length) = 0; public: /** constructor */ fr_io(fr_persist & persist); /** * destructor. * sub-classes must override it to call close() if they override close() */ virtual ~fr_io(); /** return true if this fr_io is currently (and correctly) open */ virtual bool is_open() const = 0; /** * open this fr_io. * sub-classes must override this method to perform appropriate initialization, * and the first thing sub-classes open() must do is to call super_type::open(). */ virtual int open(const fr_args & args); /** * close this fr_io. * sub-classes must override this method to perform appropriate cleanup */ virtual void close(); /** return device length (in bytes), or 0 if not open */ FT_INLINE ft_uoff dev_length() const { return this_dev_length; } /** return loop file length (in bytes), or 0 if not open */ FT_INLINE ft_uoff loop_file_length() const { return this_loop_file_length; } /** return device path, or NULL if not open */ FT_INLINE const char * dev_path() const { return this_dev_path; } /** * return umount command, or NULL if not specified by command line. * umount command is set by open(const fr_args & args). */ FT_INLINE const char * cmd_umount() const { return this_cmd_umount; } /** return log2 of effective block size, or 0 if not open */ FT_INLINE ft_uoff effective_block_size_log2() const { return this_eff_block_size_log2; } /** return job */ FT_INLINE fr_job & job() const { return this_job; } /** return job_id, or 0 if not set */ FT_INLINE ft_size job_id() const { return this_job.job_id(); } /** return job_dir, or "" if not set */ FT_INLINE const ft_string & job_dir() const { return this_job.job_dir(); } /** return storage_size to use (in bytes), or 0 if not set */ FT_INLINE ft_size job_storage_size(fr_storage_size which) const { return this_job.job_storage_size(which); } /** set storage_size to use (in bytes), or 0 to unset it */ FT_INLINE void job_storage_size(fr_storage_size which, ft_size len) { this_job.job_storage_size(which, len); } /** * return which free blocks to clear after remapping: * all, only blocks used as primary storage or renumbered device, or none */ FT_INLINE fr_clear_free_space job_clear() const { return this_job.job_clear(); } /** * set which free blocks to clear after remapping: * all, only blocks used as primary storage or renumbered device, or none */ FT_INLINE void job_clear(fr_clear_free_space clear) { this_job.job_clear(clear); } /* return the UI to use, or NULL if not set */ FT_INLINE FT_UI_NS fr_ui * ui() const { return this_ui; } /* set the UI to use. specify NULL to unset */ FT_INLINE void ui(FT_UI_NS fr_ui * ui) { this_ui = ui; } /* return the persistence to use, or NULL if not set */ FT_INLINE fr_persist & persist() const { return this_persist; } /** return true if replaying persistence */ FT_INLINE bool is_replaying() const { return this_persist.is_replaying(); } /** * return true if I/O classes should be less strict on sanity checks * and generate WARNINGS (and keep going) for failed sanity checks * instead of generating ERRORS (and quitting) */ FT_INLINE bool force_run() const { return this_job.force_run(); } /** return true if subclasses should simulate run, i.e. run WITHOUT reading or writing device blocks */ FT_INLINE bool simulate_run() const { return this_job.simulate_run(); } /** return true if program can ask questions to the user and read answers from stdin */ FT_INLINE bool ask_questions() const { return this_job.ask_questions(); } /** * if replaying an existing job, calls ff_load_extents_file() to load saved extents files. * otherwise calls the 4-argument version of read_extents() and, if it succeeds, * calls effective_block_size_log2() to compute and remember effective block size */ int read_extents(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents); /** * loads extents from files 'loop_extents.txt', 'free_space_extents.txt' and 'to_zero_extents.txt' * inside folder job.job_dir() by calling the function ff_load_extents_file() * if successful, calls effective_block_size_log2() to compute and remember effective block size */ int load_extents(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents, ft_uoff & block_size_bitmask); /** * saves extents to files 'loop_extents.txt', 'free_space_extents.txt' and 'to_zero_extents.txt' * inside folder job.job_dir() by calling the function ff_save_extents_file() */ int save_extents(const fr_vector & loop_file_extents, const fr_vector & free_space_extents, const fr_vector & to_zero_extents) const; /** * close the file descriptors for LOOP-FILE and ZERO-FILE */ virtual void close_extents() = 0; /** * get writable reference to primary_storage. * must be called before create_storage() to set the details of primary_storage */ FT_INLINE fr_vector & primary_storage() { return this_primary_storage; } /** get const reference to primary_storage */ FT_INLINE const fr_vector & primary_storage() const { return this_primary_storage; } /** * create and open SECONDARY-STORAGE job.job_dir() + '/storage.bin' and fill it with 'secondary_len' bytes of zeros. * setup a virtual storage composed by this->primary_storage extents inside DEVICE, plus secondary-storage extents. * return 0 if success, else error */ virtual int create_storage(ft_size secondary_len, ft_size mem_buffer_len) = 0; /** call umount(8) on dev_path() */ virtual int umount_dev() = 0; /** * called once by work::relocate() immediately before starting the remapping phase. * * must be overridden by sub-classes to check that last device block to be written is actually writable. * Reason: at least on Linux, if a filesystems is smaller than its containing device, it often limits to its length the writable blocks in the device. * * default implementation: do nothing and return success (0) */ virtual int check_last_block(); /** * perform buffering and coalescing of copy requests. * queues a copy of single fragment from DEVICE or FREE-STORAGE, to STORAGE to FREE-DEVICE. * calls flush_queue() as needed to actually perform any copy that cannot be buffered or coalesced. * note: parameters are in bytes! * return 0 if success, else error * * on return, this->ret_copied will be increased by the number of blocks actually copied or queued for copying, * which could be > 0 even in case of errors */ int copy_bytes(fr_dir dir, ft_uoff from_physical, ft_uoff to_physical, ft_uoff length); /** * copy a single fragment from DEVICE to FREE-STORAGE, or from STORAGE to FREE-DEVICE or from DEVICE to FREE-DEVICE * (STORAGE to FREE-STORAGE copies could be supported easily, but are not considered useful) * note: parameters are in blocks! * note: implementations may accumulate (queue) copy requests, actual copy and error reporting may be delayed until flush() * * return 0 if success, else error * * on return, this->ret_copied will be increased by the number of blocks actually copied or queued for copying, * which could be > 0 even in case of errors */ template int copy(fr_dir dir, T from_physical, T to_physical, T length) { return copy_bytes(dir, (ft_uoff)from_physical << this_eff_block_size_log2, (ft_uoff)to_physical << this_eff_block_size_log2, (ft_uoff)length << this_eff_block_size_log2); } /** * flush any pending copy (call copy_bytes() through flush_queue()), * plus flush any I/O specific buffer (call flush_bytes()) * return 0 if success, else error */ int flush(); /** * write zeroes to device (or to storage). * used to remove device-renumbered blocks once remapping is finished * and clean the remaped file-system * note: parameters are in blocks! */ template int zero(fr_to to, T offset, T length) { ft_uoff offset_bytes = (ft_uoff)offset << this_eff_block_size_log2; ft_uoff length_bytes = (ft_uoff)length << this_eff_block_size_log2; if (this_ui != 0 && !this_delegate_ui) this_ui->show_io_write(to, offset_bytes, length_bytes); return zero_bytes(to, offset_bytes, length_bytes); } /** * write zeroes to primary storage. * used to remove primary-storage once remapping is finished * and clean the remaped file-system */ virtual int zero_primary_storage() = 0; /** called after relocate() and clear_free_space(). closes storage */ virtual int close_storage() = 0; /** called to remove storage from file system if execution is completed successfully */ virtual int remove_storage_after_success(); }; FT_IO_NAMESPACE_END #endif /* FSREMAP_IO_IO_HH */ fstransform-0.9.4/fsremap/src/io/io_null.cc000066400000000000000000000112121345021500300206610ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/io_null.cc * * Created on: Mar 4, 2011 * Author: max */ #include "../first.hh" #include "../log.hh" // for ff_log() #include "../misc.hh" // for ff_pretty_size() #include "io_null.hh" // for ft_io_null FT_IO_NAMESPACE_BEGIN char const * const ft_io_null::extents_label[ft_io_null::FC_EXTENTS_FILE_COUNT] = { "DEVICE-LENGTH", "LOOP-EXTENTS", "FREE-SPACE-EXTENTS", "TO-ZERO-EXTENTS" }; char const * const ft_io_null::sim_msg = "(simulated) "; /** constructor */ ft_io_null::ft_io_null(fr_persist & persist) : super_type(persist) { /* tell job that we're a simulation */ job().simulate_run(true); } /** destructor. does nothing */ ft_io_null::~ft_io_null() { } /** * retrieve LOOP-FILE extents and FREE-SPACE extents and append them into * the vectors loop_file_extents and free_space_extents. * the vectors will be ordered by extent ->logical. * * return 0 for success, else error (and vectors contents will be UNDEFINED). * * implementation: does nothing. */ int ft_io_null::read_extents(fr_vector & FT_ARG_UNUSED(loop_file_extents), fr_vector & FT_ARG_UNUSED(free_space_extents), fr_vector & FT_ARG_UNUSED(to_zero_extents), ft_uoff & FT_ARG_UNUSED(ret_block_size_bitmask)) { return 0; } /** * close the file descriptors for LOOP-FILE and ZERO-FILE * * implementation: do nothing and return success */ void ft_io_null::close_extents() { } /** * create SECONDARY-STORAGE as job.job_dir() + '.storage' and fill it with 'len' bytes of zeros, * setup a virtual storage composed by this->primary_storage extents inside DEVICE, plus secondary-storage extents. * return 0 if success, else error * * implementation: do nothing and return success */ int ft_io_null::create_storage(ft_size secondary_len, ft_size buffer_len) { double pretty_len = 0.0; const char * pretty_label = ff_pretty_size(secondary_len, & pretty_len); ff_log(FC_INFO, 0, "%s%s is %.2f %sbytes", sim_msg, label[FC_SECONDARY_STORAGE], pretty_len, pretty_label); pretty_label = ff_pretty_size(buffer_len, & pretty_len); ff_log(FC_NOTICE, 0, "%sRAM memory buffer is %.2f %sbytes", sim_msg, pretty_len, pretty_label); return 0; } /** * call umount(8) on dev_path() * * implementation: do nothing and return success */ int ft_io_null::umount_dev() { return 0; } /** * actually copy a list of fragments from DEVICE or FREE-STORAGE, to STORAGE to FREE-DEVICE. * must be implemented by sub-classes. * note: parameters are in bytes! * return 0 if success, else error. * * implementation: do nothing and return success */ int ft_io_null::flush_copy_bytes(fr_dir FT_ARG_UNUSED(dir), fr_vector & FT_ARG_UNUSED(request_vec)) { return 0; } /** * flush any pending copy, i.e. actually perform all queued copies. * return 0 if success, else error * * implementation: do nothing and return success */ int ft_io_null::flush_bytes() { return 0; } /** * write zeroes to device (or to storage). * used to remove device-renumbered blocks once remapping is finished * * implementation: do nothing and return success */ int ft_io_null::zero_bytes(fr_to FT_ARG_UNUSED(to), ft_uoff FT_ARG_UNUSED(offset), ft_uoff FT_ARG_UNUSED(length)) { return 0; } /** * write zeroes to primary storage. * used to remove primary-storage once remapping is finished * and clean the remaped file-system * * implementation: do nothing and return success */ int ft_io_null::zero_primary_storage() { return 0; } /** * close PRIMARY-STORAGE and SECONDARY-STORAGE. called by work::close_storage() * * implementation: do nothing and return success */ int ft_io_null::close_storage() { return 0; } FT_IO_NAMESPACE_END fstransform-0.9.4/fsremap/src/io/io_null.hh000066400000000000000000000116551345021500300207060ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/io_test.hh * * Created on: Feb 28, 2011 * Author: max */ #ifndef FSREMAP_IO_IO_NULL_HH #define FSREMAP_IO_IO_NULL_HH #include "../types.hh" // for ft_uoff #include "io.hh" // for fr_io FT_IO_NAMESPACE_BEGIN /** * "null" class emulating I/O */ class ft_io_null: public fr_io { public: enum { FC_DEVICE_LENGTH = 0, FC_LOOP_EXTENTS, FC_FREE_SPACE_EXTENTS, FC_TO_ZERO_EXTENTS, FC_EXTENTS_FILE_COUNT // must be equal to count of preceding enum constants }; static char const * const extents_label[]; // DEVICE-LENGTH, LOOP-EXTENTS, FREE-SPACE-EXTENTS and TO-ZERO-EXTENTS static char const * const sim_msg; // "(simulated) " private: typedef fr_io super_type; protected: /** * retrieve LOOP-FILE extents and FREE-SPACE extents and insert them into * the vectors loop_file_extents and free_space_extents. * the vectors will be ordered by extent ->logical. * * return 0 for success, else error (and vectors contents will be UNDEFINED). * * if success, also returns in ret_effective_block_size_log2 the log2() * of device effective block size. * the device effective block size is defined as follows: * it is the largest power of 2 that exactly divides all physical, * logical and lengths in all returned extents (both for LOOP-FILE * and for FREE-SPACE) and that also exactly exactly divides device length. * * implementation: does nothing. */ virtual int read_extents(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents, ft_uoff & ret_block_size_bitmask); /** * actually copy a list of fragments from DEVICE or FREE-STORAGE, to STORAGE to FREE-DEVICE. * must be implemented by sub-classes. * note: parameters are in bytes! * return 0 if success, else error. * * implementation: do nothing and return success */ virtual int flush_copy_bytes(fr_dir dir, fr_vector & request_vec); /** * flush any pending copy, i.e. actually perform all queued copies. * return 0 if success, else error * on return, 'ret_copied' will be increased by the number of blocks actually copied (NOT queued for copying), * * implementation: do nothing and return success */ virtual int flush_bytes(); /** * write zeroes to device (or to storage). * used to remove device-renumbered blocks once remapping is finished * * implementation: do nothing and return success */ virtual int zero_bytes(fr_to to, ft_uoff offset, ft_uoff length); public: /** constructor */ ft_io_null(fr_persist & persist); /** destructor. does nothing. */ virtual ~ft_io_null(); /** * close the file descriptors for LOOP-FILE and ZERO-FILE * * implementation: do nothing and return success */ virtual void close_extents(); /** * create SECONDARY-STORAGE as job.job_dir() + '.storage' and fill it with 'len' bytes of zeros, * setup a virtual storage composed by this->primary_storage extents inside DEVICE, plus secondary-storage extents. * return 0 if success, else error * * implementation: do nothing and return success */ virtual int create_storage(ft_size secondary_len, ft_size buffer_len); /** * call umount(8) on dev_path() * * implementation: do nothing and return success */ virtual int umount_dev(); /** * write zeroes to primary storage. * used to remove primary-storage once remapping is finished * and clean the remaped file-system * * implementation: do nothing and return success */ virtual int zero_primary_storage(); /** * close PRIMARY-STORAGE and SECONDARY-STORAGE. called by work::close_storage() * * implementation: do nothing and return success */ virtual int close_storage(); }; FT_IO_NAMESPACE_END #endif /* FSREMAP_IO_IO_NULL_HH */ fstransform-0.9.4/fsremap/src/io/io_posix.cc000066400000000000000000001420001345021500300210510ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/io_posix.cc * * Created on: Feb 28, 2011 * Author: max */ #include "../first.hh" #if defined(FT_HAVE_ERRNO_H) # include // for errno #elif defined(FT_HAVE_CERRNO) # include // for errno #endif #if defined(FT_HAVE_STDIO_H) # include // for remove() #elif defined(FT_HAVE_CSTDIO) # include // for remove() #endif #if defined(FT_HAVE_STDLIB_H) # include // for malloc(), free() #elif defined(FT_HAVE_CSTDLIB) # include // for malloc(), free() #endif #if defined(FT_HAVE_STRING_H) # include // for memset() #elif defined(FT_HAVE_CSTRING) # include // for memset() #endif #ifdef FT_HAVE_SYS_TYPES_H # include // for open() #endif #ifdef FT_HAVE_SYS_STAT_H # include // " " #endif #ifdef FT_HAVE_FCNTL_H # include // " " , fallocate() #endif #ifdef FT_HAVE_UNISTD_H # include // for close() #endif #ifdef FT_HAVE_SYS_MMAN_H # include // for mmap(), munmap() #endif #include "../log.hh" // for ff_log() #include "../misc.hh" // for ff_max2(), ff_min2() #include "../ui/ui.hh" // for fr_ui #include "extent_posix.hh" // for ff_read_extents_posix() #include "util_posix.hh" // for ff_posix_*() misc functions #include "io_posix.hh" // for fr_io_posix FT_IO_NAMESPACE_BEGIN #if defined(MAP_ANONYMOUS) # define FC_MAP_ANONYMOUS MAP_ANONYMOUS #elif defined(MAP_ANON) # define FC_MAP_ANONYMOUS MAP_ANON #else # error both MAP_ANONYMOUS and MAP_ANON are missing, cannot compile io_posix.cc #endif /** default constructor */ fr_io_posix::fr_io_posix(fr_persist & persist) : super_type(persist), storage_mmap(MAP_FAILED), buffer_mmap(MAP_FAILED), storage_mmap_size(0), buffer_mmap_size(0), this_dev_blkdev(0) { /* mark fd[] as invalid: they are not open yet */ for (ft_size i = 0; i < FC_ALL_FILE_COUNT; i++) fd[i] = -1; /* tell superclass that we will invoke ui methods by ourselves */ delegate_ui(true); } /** destructor. calls close() */ fr_io_posix::~fr_io_posix() { close(); } /** return true if a single descriptor/stream is open */ bool fr_io_posix::is_open0(ft_size i) const { return fd[i] >= 0; } /** close a single descriptor/stream */ void fr_io_posix::close0(ft_size i) { if (i < FC_ALL_FILE_COUNT && fd[i] >= 0) { if (::close(fd[i]) != 0) ff_log(FC_WARN, errno, "closing %s file descriptor [%d] failed", label[i], fd[i]); fd[i] = -1; } } /** return true if this fr_io_posix is currently (and correctly) open */ bool fr_io_posix::is_open() const { return dev_length() != 0 && is_open0(FC_DEVICE); } static char const * fr_io_posix_force_msg(bool force) { if (force) return ", continuing AT YOUR OWN RISK due to '-f'"; else return ", re-run with option '-f' if you want to continue anyway (AT YOUR OWN RISK)"; }; /** open DEVICE */ int fr_io_posix::open_dev(const char * path) { enum { i = FC_DEVICE }; ft_uoff dev_len; ft_dev dev_blk; int err = open_dev0(path, & fd[i], & dev_blk, & dev_len); if (err != 0) return err; /* remember device length */ dev_length(dev_len); /* also remember device path */ dev_path(path); /* also remember device major/minor numbers */ dev_blkdev(dev_blk); double pretty_len; const char * pretty_label = ff_pretty_size(dev_len, & pretty_len); ff_log(FC_INFO, 0, "%s length is %.2f %sbytes", label[i], pretty_len, pretty_label); return err; } /** actually open DEVICE */ int fr_io_posix::open_dev0(const char * path, int * ret_fd, ft_dev * ret_dev, ft_uoff * ret_len) { enum { i = FC_DEVICE }; const bool force = force_run(); const char * force_msg = fr_io_posix_force_msg(force); int err = 0, dev_fd; do { dev_fd = ::open(path, O_RDWR); if (dev_fd < 0) { err = ff_log(FC_ERROR, errno, "error opening %s '%s'", label[i], path); break; } /* for DEVICE, we want to know its dev_t */ err = ff_posix_blkdev_dev(dev_fd, ret_dev); if (err != 0) { err = ff_log((force ? FC_WARN : FC_ERROR), err, "%sfailed %s fstat('%s')%s", (force ? "WARNING: " : ""), label[i], path, force_msg); if (force) err = 0; else break; } /* we also want to know its length */ if ((err = ff_posix_blkdev_size(dev_fd, ret_len)) != 0) { err = ff_log(FC_ERROR, err, "error in %s ioctl('%s', BLKGETSIZE64)", label[i], path); break; } } while (0); * ret_fd = dev_fd; return err; } /** open LOOP-FILE or ZERO-FILE */ int fr_io_posix::open_file(ft_size i, const char * path) { const bool force = force_run(); const char * force_msg = fr_io_posix_force_msg(force); int err = 0; ft_dev dev_dev = dev_blkdev(); bool readwrite = true; do { if (path == NULL && i == FC_ZERO_FILE) { /* zero-file is optional */ return err; } /* first, try to open everything as read-write */ fd[i] = ::open(path, O_RDWR); if (fd[i] < 0) { readwrite = false; /* then, retry to open LOOP-FILE and ZERO-FILE as read-only */ fd[i] = ::open(path, O_RDONLY); if (fd[i] < 0) { err = ff_log(FC_ERROR, errno, "error opening %s '%s'", label[i], path); break; } } /* for LOOP-FILE and ZERO-FILE, we want to know the dev_t of the device they are stored into */ ft_dev file_dev; err = ff_posix_dev(fd[i], & file_dev); if (err != 0) { err = ff_log((force ? FC_WARN : FC_ERROR), err, "failed %s fstat('%s')%s", label[i], path, force_msg); if (force) err = 0; else break; } /* for LOOP-FILE and ZERO-FILE, we also check that they are actually contained in DEVICE */ if (file_dev != dev_dev) { ff_log((force ? FC_WARN : FC_ERROR), 0, "'%s' is device 0x%04x, but %s '%s' is contained in device 0x%04x%s", dev_path(), (unsigned)dev_dev, label[i], path, (unsigned)file_dev, force_msg); if (!force) { err = -EINVAL; break; } } if (readwrite) { /* * check only now if open(O_RDWR) succeeded: * before telling the user that DEVICE is not mounted read-only, * we need to know that LOOP-FILE and ZERO-FILE are actually inside DEVICE, * otherwise the message below will mislead the user */ close0(i); ff_log(FC_ERROR, 0, "%s '%s' can be opened read-write, it means %s '%s' is not mounted read-only as it should", label[i], path, label[FC_DEVICE], dev_path()); err = -EINVAL; break; } ft_uoff len, dev_len = dev_length(); /* for LOOP-FILE and ZERO-FILE, we check their length */ if ((err = ff_posix_size(fd[i], & len)) != 0) { err = ff_log((force ? FC_WARN : FC_ERROR), err, "failed %s fstat('%s')%s", label[i], path, force_msg); if (force) err = 0; else break; } if (i == FC_LOOP_FILE) { /* remember LOOP-FILE length */ loop_file_length(len); /* * in some cases, it can happen that device has a last odd-sized block, * for example a device 1GB+1kB long with 4kB block size, * and at least on Linux it's not easy to write to the last odd-sized block: * the filesystem driver usually prevents it. * * So we play it safe and truncate device length to a multiple of its block size. * Funnily enough, a good way to get device block size is to stat() a file inside it */ ft_uoff block_size; if (ff_posix_blocksize(fd[i], & block_size) != 0) { ff_log(FC_WARN, errno, "%s fstat('%s') failed, assuming %s block size is at most 4 kilobytes", label[i], path, label[FC_DEVICE]); block_size = 4096; } else if (block_size < 512) { ff_log(FC_WARN, errno, "%s fstat('%s') reported suspiciously small block size (%" FT_ULL " bytes) for %s, rounding block size to 512 bytes", label[i], path, (ft_ull) block_size, label[FC_DEVICE]); block_size = 512; } /** remember rounded device length */ ft_uoff dev_len_rounded = dev_len - dev_len % block_size; dev_length(dev_len_rounded); if (len > dev_len_rounded) { ff_log(FC_ERROR, 0, "cannot start %sremapping: %s '%s' length (%" FT_ULL " bytes) exceeds %s '%s' size (%" FT_ULL " bytes)", (simulate_run() ? "(simulated) " : ""), label[i], path, (ft_ull)len, label[FC_DEVICE], dev_path(), (ft_ull)dev_len_rounded); if (dev_len_rounded != dev_len) { ff_log(FC_ERROR, 0, " Note: %s size is actually %" FT_ULL " bytes, " "but fsremap needs to round it down to a multiple of file-system block size (%" FT_ULL " bytes)", label[FC_DEVICE], (ft_ull)dev_len, (ft_ull)block_size); ff_log(FC_ERROR, 0, " so the usable %s size is %" FT_ULL " bytes", label[FC_DEVICE], (ft_ull)dev_len_rounded); } ff_log(FC_ERROR, 0, "Exiting, please shrink %s to %" FT_ULL " bytes or less before running fsremap again.", label[i], (ft_ull) dev_len_rounded); ff_log(FC_ERROR, 0, " (if you are using fstransform - i.e. if you did not manually run fsremap - " "then this is a BUG in fstransform, please report it)"); err = -EFBIG; break; } else if (len < dev_len_rounded) { ff_log(FC_INFO, 0, "%s '%s' is shorter than %s, remapping will also shrink file-system", label[i], path, label[FC_DEVICE]); } } } while (0); return err; } /** check for consistency and open DEVICE, LOOP-FILE and ZERO-FILE */ int fr_io_posix::open(const fr_args & args) { if (is_open()) { // already open! ff_log(FC_ERROR, 0, "unexpected call, I/O is already open"); return -EISCONN; } int err = super_type::open(args); if (err != 0) return err; #ifdef FT_HAVE_GETUID if (getuid() != 0) ff_log(FC_WARN, 0, "not running as root! expect '%s' errors", strerror(EPERM)); #endif char const* const* path = args.io_args; do { ft_size i = FC_DEVICE; if ((err = open_dev(path[i])) != 0) break; if (!is_replaying()) for (i = FC_DEVICE + 1; i < FC_FILE_COUNT; i++) if ((err = open_file(i, path[i])) != 0) break; } while (0); if (err != 0) close(); return err; } /** close this I/O, including file descriptors to DEVICE, LOOP-FILE, ZERO-FILE and SECONDARY-STORAGE */ void fr_io_posix::close() { for (ft_size i = 0; i < FC_FILE_COUNT; i++) close0(i); close_storage(); super_type::close(); } /** return true if this I/O has open descriptors/streams to LOOP-FILE and FREE-SPACE */ bool fr_io_posix::is_open_extents() const { /* FREE-SPACE is optional, do not check if it's open */ return dev_length() != 0 && is_open0(FC_LOOP_FILE); } /** * retrieve LOOP-FILE extents, FREE-SPACE extents and any additional extents to be ZEROED * and insert them into the vectors loop_file_extents, free_space_extents and to_zero_extents * the vectors will be ordered by extent ->logical (for to_zero_extents, ->physical and ->logical will be the same). * * return 0 for success, else error (and vectors contents will be UNDEFINED). * * if success, also returns in ret_effective_block_size_log2 the log2() * of device effective block size. * the device effective block size is defined as follows: * it is the largest power of 2 that exactly divides all physical, * logical and lengths in all returned extents (both for LOOP-FILE * and for FREE-SPACE) and that also exactly exactly divides device length. * * must be overridden by sub-classes. * * the trick fr_io_posix uses to implement this method * is to fill the device's free space with a ZERO-FILE, * and actually retrieve the extents used by ZERO-FILE. */ int fr_io_posix::read_extents(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents, ft_uoff & ret_block_size_bitmask) { ft_uoff block_size_bitmask = ret_block_size_bitmask; int err = 0; do { if (!is_open_extents()) { ff_log(FC_ERROR, 0, "unexpected call to io_posix::read_extents(), I/O is not open"); err = -ENOTCONN; // not open! break; } if ((err = read_extents_loop_file(loop_file_extents, to_zero_extents, block_size_bitmask)) != 0) break; if ((err = read_extents_free_space(loop_file_extents, free_space_extents, to_zero_extents, block_size_bitmask)) != 0) break; } while (0); if (err == 0) ret_block_size_bitmask = block_size_bitmask; return err; } /** * retrieve LOOP-FILE extents and any additional extents to be ZEROED * and insert them into the vectors loop_file_extents, and to_zero_extents * the vectors will be ordered by extent ->logical (for to_zero_extents, ->physical and ->logical will be the same). * * return 0 for success, else error (and vectors contents will be UNDEFINED). * * if success, also update the parameter ret_effective_block_size_log2 to be the log2() * of device effective block size (see read_extents() for detailed meaning of this parameter) */ int fr_io_posix::read_extents_loop_file(fr_vector & loop_file_extents, fr_vector & FT_ARG_UNUSED(to_zero_extents), ft_uoff & ret_block_size_bitmask) { ft_uoff block_size_bitmask = ret_block_size_bitmask; int err = 0; do { if (!is_open_extents()) { ff_log(FC_ERROR, 0, "unexpected call to io_posix::read_extents_loop_file(), I/O is not open"); err = -ENOTCONN; // not open! break; } ft_uoff dev_len = dev_length(); /* ff_read_extents_posix() appends into fr_vector, does NOT overwrite it */ if ((err = ff_read_extents_posix(fd[FC_LOOP_FILE], dev_len, loop_file_extents, block_size_bitmask)) != 0) break; } while (0); if (err == 0) ret_block_size_bitmask = block_size_bitmask; return err; } /** * retrieve FREE-SPACE extents and any additional extents to be ZEROED * and insert them into the vectors free_space_extents, and to_zero_extents * the vectors will be ordered by extent ->logical (for to_zero_extents, ->physical and ->logical will be the same). * * return 0 for success, else error (and vectors contents will be UNDEFINED). * * if success, also update the parameter ret_effective_block_size_log2 to be the log2() * of device effective block size (see read_extents() for detailed meaning of this parameter) */ int fr_io_posix::read_extents_free_space(const fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & FT_ARG_UNUSED(to_zero_extents), ft_uoff & ret_block_size_bitmask) { ft_uoff block_size_bitmask = ret_block_size_bitmask; int err = 0; do { if (!is_open_extents()) { ff_log(FC_ERROR, 0, "unexpected call to io_posix::read_extents_free_space(), I/O is not open"); err = -ENOTCONN; // not open! break; } ft_uoff dev_len = dev_length(); if (fd[FC_ZERO_FILE] >= 0) { if ((err = ff_read_extents_posix(fd[FC_ZERO_FILE], dev_len, free_space_extents, block_size_bitmask)) != 0) break; } else { block_size_bitmask |= dev_len; /* * ZERO-FILE is optional. * if not specified, prepare for an irreversible remapping that does not preserve DEVICE: * consider *ALL* extents outside LOOP-FILE as free */ free_space_extents = loop_file_extents; free_space_extents.sort_by_physical(); fr_map free_map; free_map.complement0_physical_shift(free_space_extents, 0, dev_len); free_space_extents.clear(); fr_map::const_iterator iter, end = free_map.end(); for (iter = free_map.begin(); iter != end; ++iter) free_space_extents.append(*iter); } } while (0); if (err == 0) ret_block_size_bitmask = block_size_bitmask; return err; } /** * close the file descriptors for LOOP-FILE and ZERO-FILE */ void fr_io_posix::close_extents() { close0(FC_ZERO_FILE); close0(FC_LOOP_FILE); } /** * close and munmap() SECONDARY-STORAGE. does NOT remove it from file system! * called by close() and by work::close_storage() */ int fr_io_posix::close_storage() { int err = 0; enum { i = FC_PRIMARY_STORAGE, j = FC_SECONDARY_STORAGE }; if (storage_mmap != MAP_FAILED) { if (munmap(storage_mmap, storage_mmap_size) == 0) { storage_mmap = MAP_FAILED; storage_mmap_size = 0; } else { bool flag_i = !primary_storage().empty(); bool flag_j = secondary_storage().length() != 0; err = ff_log(FC_WARN, errno, "warning: %s%s%s munmap() failed", (flag_i ? label[i] : ""), (flag_i && flag_j ? " and " : ""), (flag_j ? label[j] : "") ); } } if (err == 0 && buffer_mmap != MAP_FAILED) { if (munmap(buffer_mmap, buffer_mmap_size) == 0) { buffer_mmap = MAP_FAILED; buffer_mmap_size = 0; } else { err = ff_log(FC_WARN, errno, "warning: memory buffer munmap() failed"); } } if (err == 0) { close0(i); close0(j); } return err; } /** * create and open SECONDARY-STORAGE job.job_dir() + '.storage', * fill it with 'secondary_len' bytes of zeros and mmap() it. * * then mmap() this->primary_storage extents. * finally setup a virtual storage composed by 'primary_storage' extents inside DEVICE, plus secondary-storage extents. * * return 0 if success, else error */ int fr_io_posix::create_storage(ft_size secondary_size, ft_size mem_buffer_size) { /* * how to get a contiguous mmapped() memory for all the extents in primary_storage and secondary_storage: * * mmap(MAP_ANON/MAP_ANONYMOUS) the total storage size (sum(primary_storage->length)+secondary_len) * then incrementally replace parts of it with munmap() followed by mmap(MAP_FIXED) of each storage extent */ enum { i = FC_PRIMARY_STORAGE, j = FC_SECONDARY_STORAGE }; if (storage_mmap != MAP_FAILED || is_open0(j)) { // already initialized! ff_log(FC_ERROR, 0, "unexpected call to create_storage(), %s is already initialized", storage_mmap != MAP_FAILED ? label[i] : label[j]); // return error as already reported return -EISCONN; } /** * recompute primary_len... we could receive it from caller, but it's redundant * and in any case we will still need to iterate on primary_storage to mmap() it */ ft_uoff primary_len = 0; fr_vector::iterator begin = primary_storage().begin(), iter, end = primary_storage().end(); for (iter = begin; iter != end; ++iter) { primary_len += iter->second.length; } double pretty_len; const char * pretty_label; int err = 0; do { const ft_size mmap_size = (ft_size) primary_len + secondary_size; if (primary_len > (ft_size)-1 - secondary_size) { err = ff_log(FC_FATAL, EOVERFLOW, "internal error, %s + %s total length = %" FT_ULL " is larger than addressable memory", label[i], label[j], (ft_ull) primary_len + secondary_size); break; } /* * mmap() total length as PROT_NONE, FC_MAP_ANONYMOUS. * used to reserve a large enough contiguous memory area * to mmap() PRIMARY STORAGE and SECONDARY STORAGE */ storage_mmap = mmap(NULL, mmap_size, PROT_NONE, MAP_PRIVATE|FC_MAP_ANONYMOUS, -1, 0); if (storage_mmap == MAP_FAILED) { err = ff_log(FC_ERROR, errno, "%s: error preemptively reserving contiguous RAM: mmap(length = %" FT_ULL ", PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1) failed", label[FC_STORAGE], (ft_ull) mmap_size); break; } else ff_log(FC_DEBUG, 0, "%s: preemptively reserved contiguous RAM," " mmap(length = %" FT_ULL ", PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1) = ok", label[FC_STORAGE], (ft_ull) mmap_size); storage_mmap_size = mmap_size; /* * mmap() another area, mem_buffer_size bytes long, as PROT_READ|PROT_WRITE, FC_MAP_ANONYMOUS. * used as memory buffer during DEV2DEV copies */ buffer_mmap = mmap(NULL, mem_buffer_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|FC_MAP_ANONYMOUS, -1, 0); if (buffer_mmap == MAP_FAILED) { err = ff_log(FC_ERROR, errno, "%s: error allocating memory buffer: mmap(length = %" FT_ULL ", PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1) failed", label[FC_STORAGE], (ft_ull) mem_buffer_size); break; } /* * we could mlock(buffer_mmap), but it's probably excessive * as it constraints too much the kernel in deciding the memory to swap to disk. * * instead, we opt for a simple memset(), which forces the kernel to actually allocate * the RAM for us (we do not want memory overcommit errors later on), * but still let the kernel decide what to swap to disk */ memset(buffer_mmap, '\0', buffer_mmap_size = mem_buffer_size); pretty_len = 0.0; pretty_label = ff_pretty_size(buffer_mmap_size, & pretty_len); ff_log(FC_NOTICE, 0, "allocated %.2f %sbytes RAM as memory buffer", pretty_len, pretty_label); if (secondary_size != 0) { if ((err = create_secondary_storage(secondary_size)) != 0) break; } else ff_log(FC_INFO, 0, "not creating %s, %s is large enough", label[j], label[i]); /* now incrementally replace storage_mmap with actually mmapped() storage extents */ begin = primary_storage().begin(); end = primary_storage().end(); ft_size mem_offset = 0; for (iter = begin; err == 0 && iter != end; ++iter) err = replace_storage_mmap(fd[FC_DEVICE], label[i], *iter, iter-begin, mem_offset); if (err != 0) break; if (secondary_size != 0) { if ((err = replace_storage_mmap(fd[j], label[j], secondary_storage(), 0, mem_offset)) != 0) break; } if (mem_offset != storage_mmap_size) { ff_log(FC_FATAL, 0, "internal error, mapped %s extents in RAM used %" FT_ULL " bytes instead of expected %" FT_ULL " bytes", label[FC_STORAGE], (ft_ull) mem_offset, (ft_ull) storage_mmap_size); err = EINVAL; } } while (0); if (err == 0) { pretty_len = 0.0; pretty_label = ff_pretty_size(storage_mmap_size, & pretty_len); ff_log(FC_NOTICE, 0, "%s%s%s is %.2f %sbytes, initialized and mmapped() to contiguous RAM", (primary_len != 0 ? label[i] : ""), (primary_len != 0 && secondary_size != 0 ? " + " : ""), (secondary_size != 0 ? label[j] : ""), pretty_len, pretty_label); } else close_storage(); return err; } /** * replace a part of the mmapped() storage_mmap area with specified storage_extent, * and store mmapped() address into storage_extent.user_data(). * return 0 if success, else error * * note: fd shoud be this->fd[FC_DEVICE] for primary storage, * or this->fd[FC_SECONDARY_STORAGE] for secondary storage */ int fr_io_posix::replace_storage_mmap(int fd, const char * label_i, fr_extent & storage_extent, ft_size extent_index, ft_size & ret_mem_offset) { ft_size len = (ft_size) storage_extent.length(); ft_size mem_start = ret_mem_offset, mem_end = mem_start + len; int err = 0; do { if (mem_start >= storage_mmap_size || mem_end > storage_mmap_size) { ff_log(FC_FATAL, 0, "internal error mapping %s extent #%" FT_ULL " in RAM!" " extent (%" FT_ULL ", length = %" FT_ULL ") overflows total %s length = %" FT_ULL , label_i, (ft_ull) extent_index, (ft_ull) mem_start, (ft_ull) len, label[FC_STORAGE], (ft_ull) storage_mmap_size); /* mark error as reported */ err = -EINVAL; break; } void * addr_old = (char *) storage_mmap + mem_start; if (munmap(addr_old, len) != 0) { err = ff_log(FC_ERROR, errno, "error mapping %s extent #%" FT_ULL " in RAM," " munmap(address + %" FT_ULL ", length = %" FT_ULL ") failed", label_i, (ft_ull) extent_index, (ft_ull) mem_start, (ft_ull) len); break; } void * addr_new = mmap(addr_old, len, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, storage_extent.physical()); if (addr_new == MAP_FAILED) { err = ff_log(FC_ERROR, errno, "error mapping %s extent #%" FT_ULL " in RAM," " mmap(address + %" FT_ULL ", length = %" FT_ULL ", MAP_FIXED) failed", label_i, (ft_ull) extent_index, (ft_ull) mem_start, (ft_ull) len); break; } if (addr_new != addr_old) { ff_log(FC_ERROR, 0, "error mapping %s extent #%" FT_ULL " in RAM," " mmap(address + %" FT_ULL ", length = %" FT_ULL ", MAP_FIXED)" " violated MAP_FIXED and returned a different address", label_i, (ft_ull) extent_index, (ft_ull) mem_start, (ft_ull) len); /* mark error as reported */ err = -EFAULT; /** try at least to munmap() this problematic extent */ if (munmap(addr_new, len) != 0) { ff_log(FC_WARN, errno, "weird OS! not only mmap() violated MAP_FIXED, but subsequent munmap() failed too"); } break; } ff_log(FC_TRACE, 0, "%s extent #%" FT_ULL " mapped in RAM," " mmap(address + %" FT_ULL ", length = %" FT_ULL ", MAP_FIXED) = ok", label_i, (ft_ull) extent_index, (ft_ull) mem_start, (ft_ull) len); #ifdef FT_HAVE_MLOCK if (!simulate_run() && mlock(addr_new, len) != 0) { ff_log(FC_WARN, errno, "%s extent #%" FT_ULL " mlock(address + %" FT_ULL ", length = %" FT_ULL ") failed", label_i, (ft_ull) extent_index, (ft_ull) mem_start, (ft_ull) len); } #else #warning mlock() not found on this platform. fsremap will be vulnerable to memory exhaustion from other programs static bool warned_no_mlock = false; if (!warned_no_mlock) { warned_no_mlock = true; ff_log(FC_WARN, 0, "fsremap was compiled without support for mlock()"); ff_log(FC_WARN, 0, "for the safety of your data, please do not start memory-hungry programs while fsremap is running"); } #endif /** * all ok, let's store mmapped() address offset into extent.user_data to remember it, * as msync() inside flush() and munmap() inside close_storage() could need it */ storage_extent.user_data() = mem_start; /* and remember to update ret_mem_offset */ ret_mem_offset += len; } while (0); return err; } /** * create and open SECONDARY-STORAGE in job.job_dir() + '.storage' * and fill it with 'secondary_len' bytes of zeros. do not mmap() it. * return 0 if success, else error */ int fr_io_posix::create_secondary_storage(ft_size len) { enum { j = FC_SECONDARY_STORAGE }; ft_string filepath = job_dir(); filepath += "/storage.bin"; const char * path = filepath.c_str(); int err = 0; const bool simulated = simulate_run(); const bool replaying = is_replaying(); do { const ft_off s_len = (ft_off) len; if (s_len < 0 || len != (ft_size) s_len) { err = ff_log(FC_FATAL, EOVERFLOW, "internal error, %s length = %" FT_ULL " overflows type (off_t)", label[j], (ft_ull) len); break; } double pretty_len = 0.0; const char * pretty_label = ff_pretty_size(len, & pretty_len); const char * simulated_msg = simulated ? " (simulated)" : ""; if ((fd[j] = ::open(path, replaying ? O_RDWR : O_RDWR|O_CREAT|O_TRUNC, 0600)) < 0) { err = ff_log(FC_ERROR, errno, "error in %s open('%s')", label[j], path); if (replaying && err == -ENOENT) ff_log(FC_ERROR, 0, "you probably tried to resume a COMPLETED job"); break; } if (replaying) { ft_uoff actual_len = 0; err = ff_posix_size(fd[j], & actual_len); if (err != 0) { err = ff_log(FC_ERROR, err, "%s: fstat('%s') failed", label[j], path); } else if (actual_len != (ft_uoff) len) { ff_log(FC_ERROR, 0, "%s: file '%s' is %" FT_ULL " bytes long, expecting %" FT_ULL " bytes instead", label[j], path, (ft_ull) actual_len, (ft_ull) len); err = -EINVAL; } else ff_log(FC_INFO, 0, "%s: opened existing file '%s', is %.2f %sbytes long", label[j], path, pretty_len, pretty_label); } else { ff_log(FC_INFO, 0, "%s:%s writing %.2f %sbytes to '%s' ...", label[j], simulated_msg, pretty_len, pretty_label, path); if (simulated) { if ((err = ff_posix_lseek(fd[j], len - 1)) != 0) { err = ff_log(FC_ERROR, errno, "error in %s lseek('%s', offset = %" FT_ULL " - 1)", label[j], path, (ft_ull)len); break; } char zero = '\0'; if ((err = ff_posix_write(fd[j], & zero, 1)) != 0) { err = ff_log(FC_ERROR, errno, "error in %s write('%s', '\\0', length = 1)", label[j], path); break; } } else { ft_string err_msg = ft_string("error in ") + label[j] + "write('" + path + "')"; err = ff_posix_fallocate(fd[j], s_len, err_msg); } if (err == 0) ff_log(FC_INFO, 0, "%s:%s file created", label[j], simulated_msg); } if (err != 0) break; /* remember secondary_storage details */ fr_extent & extent = secondary_storage(); extent.physical() = extent.logical() = 0; extent.length() = len; } while (0); if (err != 0) { const bool need_remove = !replaying && is_open0(j); close0(fd[j]); if (need_remove && remove(path) != 0 && errno != ENOENT) ff_log(FC_WARN, errno, "removing %s file '%s' failed", label[j], path); } return err; } /** * called to remove SECONDARY-STORAGE file job.job_dir() + '/storage.bin' from file system * if execution is completed successfully * return 0 if success, else error */ int fr_io_posix::remove_storage_after_success() { enum { j = FC_SECONDARY_STORAGE }; ft_string filepath = job_dir(); filepath += "/storage.bin"; const char * path = filepath.c_str(); if (remove(path) != 0 && errno != ENOENT) ff_log(FC_WARN, errno, "removing %s file '%s' failed", label[j], path); return 0; } /** call umount(8) on dev_path() */ int fr_io_posix::umount_dev() { const char * cmd = cmd_umount(), * dev = dev_path(); std::vector args; if (cmd == NULL) // posix standard name for umount(8) cmd = "/bin/umount"; args.push_back(cmd); // only one argument: device path args.push_back(dev); args.push_back(NULL); // needed by ff_posix_exec() as end-of-arguments marker ff_log(FC_INFO, 0, "unmounting %s '%s'... command: %s %s", label[FC_DEVICE], dev, cmd, dev); int err = ff_posix_exec(args[0], & args[0]); if (err == 0) ff_log(FC_NOTICE, 0, "successfully unmounted %s '%s'", label[FC_DEVICE], dev); (void) sync(); // sync() returns void return err; } /** * called once by work::relocate() immediately before starting the remapping phase. * * checks that last device block to be written is actually writable. * Reason: if linux filesystems are smaller than the device, they often limit the writable blocks in the device to their length. */ int fr_io_posix::check_last_block() { ft_uoff loop_file_len = loop_file_length(); int err = 0; if (loop_file_len-- == 0) return err; const char * label_dev = label[FC_DEVICE]; int fd_dev = fd[FC_DEVICE]; char ch = '\0'; bool simulated = simulate_run(); for (int i = 0; err == 0 && i < 2; i++) { if ((err = ff_posix_lseek(fd_dev, loop_file_len)) != 0) { err = ff_log(FC_ERROR, err, "I/O error in %s lseek(fd = %d, offset = %" FT_ULL ", SEEK_SET)", label_dev, fd_dev, (ft_ull)loop_file_len); break; } if (i == 0) { if ((err = ff_posix_read(fd_dev, &ch, 1)) != 0) err = ff_log(FC_ERROR, err, "I/O error in %s read(fd = %d, offset = %" FT_ULL ", len = 1)", label_dev, fd_dev, (ft_ull)loop_file_len); } else if (!simulated) { if ((err = ff_posix_write(fd_dev, &ch, 1)) != 0) err = ff_log(FC_ERROR, err, "last position to be written into %s (offset = %" FT_ULL ") is NOT writable", label_dev, (ft_ull)loop_file_len); } } return err; } /** * actually copy a list of fragments from DEVICE to STORAGE, or from STORAGE or DEVICE, or from DEVICE to DEVICE. * note: parameters are in bytes! * return 0 if success, else error. * * we expect request_vec to be sorted by ->physical (i.e. ->from_physical) */ int fr_io_posix::flush_copy_bytes(fr_dir dir, fr_vector & request_vec) { int err = 0; switch (dir) { case FC_DEV2STORAGE: { /* from DEVICE to memory-mapped STORAGE */ /* sequential disk access: request_vec is supposed to be already sorted by device from_offset, i.e. extent->physical */ fr_vector::const_iterator iter = request_vec.begin(), end = request_vec.end(); for (; err == 0 && iter != end; ++iter) err = flush_copy_bytes(FC_POSIX_DEV2STORAGE, *iter); break; } case FC_STORAGE2DEV: { /* from memory-mapped STORAGE to DEVICE */ /* sequential disk access: request_vec is supposed to be already sorted by device to_offset, i.e. extent->logical */ fr_vector::const_iterator iter = request_vec.begin(), end = request_vec.end(); for (; err == 0 && iter != end; ++iter) err = flush_copy_bytes(FC_POSIX_STORAGE2DEV, *iter); break; } case FC_DEV2DEV: { /* from DEVICE to DEVICE, using RAM buffer */ /* sequential disk access: request_vec is supposed to be sorted by device to_offset, i.e. extent->logical */ request_vec.sort_by_physical(); /* sort by device from_offset, i.e. extent->physical */ ft_uoff from_offset, to_offset, length; ft_size buf_offset = 0, buf_free = buffer_mmap_size, buf_length; ft_size start = 0, i = start, save_i, n = request_vec.size(); do { /* iterate and fill buffer_mmap */ for (; err == 0 && buf_free != 0 && i < n; ++i) { fr_extent & extent = request_vec[i]; if ((length = extent.length()) > (ft_uoff) buf_free) break; if ((err = flush_copy_bytes(FC_POSIX_DEV2RAM, extent.physical(), (ft_uoff)(extent.user_data() = buf_offset), length)) != 0) break; buf_offset += (ft_size) length; buf_free -= (ft_size) length; } if (err != 0) break; /* buffer_mmap is now (almost) full. sort buffered data by device to_offset (i.e. extent->logical) and write it to target */ if ((save_i = i) != start) { request_vec.sort_by_logical(request_vec.begin() + start, request_vec.begin() + i); for (i = start; err == 0 && i != save_i; ++i) { fr_extent & extent = request_vec[i]; if ((err = flush_copy_bytes(FC_POSIX_RAM2DEV, (ft_uoff) extent.user_data(), extent.logical(), extent.length())) != 0) break; } } if (err != 0 || (err = flush_bytes()) != 0) break; /* buffered data written to target. now there may be one or more extents NOT fitting into buffer_mmap */ buf_offset = 0, buf_free = buffer_mmap_size; for (i = save_i; err == 0 && i != n; ++i) { fr_extent & extent = request_vec[i]; if ((length = extent.length()) <= buf_free) break; from_offset = extent.physical(); to_offset = extent.logical(); while (length != 0) { buf_length = (ft_size) ff_min2(length, buf_free); if ((err = flush_copy_bytes(FC_POSIX_DEV2RAM, from_offset, buf_offset, buf_length)) != 0 || (err = flush_copy_bytes(FC_POSIX_RAM2DEV, buf_offset, to_offset, buf_length)) != 0 || (err = flush_bytes()) != 0) break; length -= (ft_uoff) buf_length; from_offset += (ft_uoff) buf_length; to_offset += (ft_uoff) buf_length; } if (err != 0) break; } } while (err == 0 && (start = i) != n); break; } default: /* from STORAGE to STORAGE */ err = ff_log(FC_FATAL, ENOSYS, "internal error! unexpected call to io_posix.copy_bytes(), STORAGE to STORAGE copies are not supposed to be used"); break; } return err; } int fr_io_posix::flush_copy_bytes(fr_dir_posix dir, const fr_extent & request) { return flush_copy_bytes(dir, request.physical(), request.logical(), request.length()); } #undef ENABLE_CHECK_IF_MEM_IS_ZERO #ifdef ENABLE_CHECK_IF_MEM_IS_ZERO /** returns true if the specified memory range contains ONLY zeroes. */ static bool fr_io_posix_mem_is_zero(const char * mem_address, ft_size mem_length) { for (ft_size i = 0; i < mem_length; i++) { if (mem_address[i] != 0) return false; } return true; } #endif // ENABLE_CHECK_IF_MEM_IS_ZERO int fr_io_posix::flush_copy_bytes(fr_dir_posix dir, ft_uoff from_offset, ft_uoff to_offset, ft_uoff length) { const bool use_storage = dir == FC_POSIX_DEV2STORAGE || dir == FC_POSIX_STORAGE2DEV; const bool read_dev = dir == FC_POSIX_DEV2STORAGE || dir == FC_POSIX_DEV2RAM; const char * label_dev = label[FC_DEVICE]; const char * label_other = use_storage ? label[FC_STORAGE] : "RAM"; const char * label_from = read_dev ? label_dev : label_other; const char * label_to = read_dev ? label_other : label_dev; const ft_size mmap_size = use_storage ? storage_mmap_size : buffer_mmap_size; const ft_uoff dev_offset = read_dev ? from_offset : to_offset; const ft_uoff other_offset = read_dev ? to_offset : from_offset; /* validate("label", N, ...) also checks if from/to + length overflows (ft_uoff)-1 */ int err = validate("ft_uoff", (ft_uoff)-1, dir, from_offset, to_offset, length); if (err == 0) err = validate("ft_size", (ft_uoff)mmap_size, dir, 0, other_offset, length); if (err != 0) return err; const ft_size mem_offset = (ft_size)other_offset; const ft_size mem_length = (ft_size)length; char * mmap_address = use_storage ? (char *)storage_mmap : (char *)buffer_mmap; const int fd = this->fd[FC_DEVICE]; const bool simulated = simulate_run(); if (ui() != NULL) { if (dir != FC_POSIX_RAM2DEV) { fr_from from = dir == FC_POSIX_STORAGE2DEV ? FC_FROM_STORAGE : FC_FROM_DEV; ui()->show_io_read(from, from_offset, length); } if (dir!= FC_POSIX_DEV2RAM) { fr_to to = dir == FC_POSIX_DEV2STORAGE ? FC_TO_STORAGE : FC_TO_DEV; ui()->show_io_write(to, to_offset, length); } } do { if (!simulated) { if ((err = ff_posix_lseek(fd, dev_offset)) != 0) { err = ff_log(FC_ERROR, err, "I/O error in %s lseek(fd = %d, offset = %" FT_ULL ", SEEK_SET)", label_dev, fd, (ft_ull)dev_offset); break; } #define CURRENT_OP_FMT "from %s to %s, %s({fd = %d, offset = %" FT_ULL "}, address + %" FT_ULL ", length = %" FT_ULL ")" #define CURRENT_OP_ARGS label_from, label_to, (read_dev ? "read" : "write"), fd, (ft_ull)dev_offset, (ft_ull)mem_offset, (ft_ull)mem_length #ifdef ENABLE_CHECK_IF_MEM_IS_ZERO # define CHECK_IF_MEM_IS_ZERO \ do { \ if (fr_io_posix_mem_is_zero(mmap_address + mem_offset, mem_length)) { \ ff_log(FC_WARN, 0, "found an extent full of zeros copying " CURRENT_OP_FMT ". Stopping, press ENTER to continue.", CURRENT_OP_ARGS); \ char ch; \ (void) ff_posix_read(0, &ch, 1); \ } \ } while (0) #else // !ENABLE_CHECK_IF_MEM_IS_ZERO # define CHECK_IF_MEM_IS_ZERO do { } while (0) #endif // ENABLE_CHECK_IF_MEM_IS_ZERO if (read_dev) { err = ff_posix_read(fd, mmap_address + mem_offset, mem_length); if (err == 0) { CHECK_IF_MEM_IS_ZERO; } } else { CHECK_IF_MEM_IS_ZERO; err = ff_posix_write(fd, mmap_address + mem_offset, mem_length); } if (err != 0) { err = ff_log(FC_ERROR, err, "I/O error while copying " CURRENT_OP_FMT, CURRENT_OP_ARGS); break; } } ff_log(FC_TRACE, 0, "%scopy " CURRENT_OP_FMT " = ok", (simulated ? "(simulated) " : ""), CURRENT_OP_ARGS); } while (0); return err; } /* return (-)EOVERFLOW if request from/to + length overflow specified maximum value */ int fr_io_posix::validate(const char * type_name, ft_uoff type_max, fr_dir_posix dir2, ft_uoff from, ft_uoff to, ft_uoff length) { fr_dir dir; switch (dir2) { case FC_POSIX_STORAGE2DEV: dir = FC_STORAGE2DEV; break; case FC_POSIX_DEV2STORAGE: dir = FC_DEV2STORAGE; break; case FC_POSIX_DEV2RAM: case FC_POSIX_RAM2DEV: dir = FC_DEV2DEV; break; default: dir = FC_INVALID2INVALID; break; } return super_type::validate(type_name, type_max, dir, from, to, length); } /** * flush any I/O specific buffer * return 0 if success, else error * implementation: call msync() because we use a mmapped() buffer for STORAGE, * and call sync() because we write() to DEVICE */ int fr_io_posix::flush_bytes() { int err = 0; do { if (ui() != NULL) ui()->show_io_flush(); if (simulate_run()) break; #if 1 if ((err = msync(storage_mmap, storage_mmap_size, MS_SYNC)) != 0) { ff_log(FC_WARN, errno, "I/O error in %s msync(address + %" FT_ULL ", length = %" FT_ULL ")", label[FC_STORAGE], (ft_ull)0, (ft_ull)storage_mmap_size); err = 0; } #else fr_vector::const_iterator begin = primary_storage().begin(), iter, end = primary_storage().end(); for (iter = begin; iter != end; ++iter) msync_bytes(*iter); if (secondary_storage().length() != 0) msync_bytes(secondary_storage()); #endif (void) sync(); // sync() returns void #if 0 if (err != 0) { ff_log(FC_WARN, errno, "I/O error in sync()"); err = 0; } #endif } while (0); return err; } /** internal method, called by flush_bytes() to perform msync() on mmapped storage */ int fr_io_posix::msync_bytes(const fr_extent & extent) const { ft_uoff mem_offset = extent.second.user_data; ft_size mem_length = (ft_size) extent.second.length; // check for overflow? int err; if ((err = msync((char *)storage_mmap + mem_offset, mem_length, MS_SYNC)) != 0) { ff_log(FC_WARN, errno, "I/O error in %s msync(address + %" FT_ULL ", length = %" FT_ULL ")", label[FC_STORAGE], (ft_ull)mem_offset, (ft_ull)mem_length); err = 0; } return err; } /** * write zeroes to device (or to storage). * used to remove device-renumbered blocks once remapping is finished */ int fr_io_posix::zero_bytes(fr_to to, ft_uoff offset, ft_uoff length) { static char * zero_buf = NULL; enum { ZERO_BUF_LEN = 1024*1024 }; ft_uoff max = to == FC_TO_DEV ? dev_length() : (ft_uoff) storage_mmap_size; int err = 0; do { if (!ff_can_sum(offset, length) || length > max || offset > max - length) { err = ff_log(FC_FATAL, EOVERFLOW, "internal error! %s io.zero(to = %d, offset = %" FT_ULL ", length = %" FT_ULL ")" " overflows maximum allowed %" FT_ULL , label[to == FC_TO_DEV ? FC_DEVICE : FC_STORAGE], (int)to, (ft_ull)offset, (ft_ull)length, (ft_ull)max); break; } if (ui() != NULL) ui()->show_io_write(to, offset, length); if (simulate_run()) break; if (to == FC_TO_STORAGE) { memset((char *) storage_mmap + (ft_size)offset, '\0', (ft_size)length); break; } /* else (to == FC_TO_DEVICE) */ if (zero_buf == NULL) { if ((zero_buf = (char *) malloc(ZERO_BUF_LEN)) == NULL) return ENOMEM; memset(zero_buf, '\0', ZERO_BUF_LEN); } int dev_fd = fd[FC_DEVICE]; if ((err = ff_posix_lseek(dev_fd, offset)) != 0) { err = ff_log(FC_ERROR, err, "error in %s lseek(fd = %d, offset = %" FT_ULL ")", label[FC_DEVICE], dev_fd, (ft_ull) offset); break; } ft_uoff chunk; while (length != 0) { chunk = ff_min2(length, ZERO_BUF_LEN); if ((err = ff_posix_write(dev_fd, zero_buf, chunk)) != 0) { err = ff_log(FC_ERROR, err, "error in %s write({fd = %d, offset = %" FT_ULL "}, zero_buffer, length = %" FT_ULL ")", label[FC_DEVICE], dev_fd, (ft_ull) offset, (ft_ull) chunk); break; } length -= chunk; } } while (0); return err; } /** * write zeroes to primary storage. * used to remove primary-storage once remapping is finished * and clean the remaped file-system */ int fr_io_posix::zero_primary_storage() { fr_vector::const_iterator begin = primary_storage().begin(), iter, end = primary_storage().end(); ft_size mem_offset, mem_length; const bool simulated = simulate_run(); FT_UI_NS fr_ui * this_ui = ui(); for (iter = begin; iter != end; ++iter) { const fr_extent & extent = *iter; mem_offset = extent.second.user_data; mem_length = (ft_size) extent.second.length; // check for overflow? if (this_ui != NULL) this_ui->show_io_write(FC_TO_STORAGE, mem_offset, mem_length); if (!simulated) memset((char *) storage_mmap + mem_offset, '\0', mem_length); } return 0; } FT_IO_NAMESPACE_END fstransform-0.9.4/fsremap/src/io/io_posix.hh000066400000000000000000000237731345021500300211020ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/io_posix.hh * * Created on: Feb 28, 2011 * Author: max */ #ifndef FSREMAP_IO_IO_POSIX_HH #define FSREMAP_IO_IO_POSIX_HH #include "../types.hh" /* for ft_uoff */ #include "io.hh" /* for fr_io */ FT_IO_NAMESPACE_BEGIN /** * class performing I/O on POSIX systems */ class fr_io_posix: public fr_io { public: enum { FC_DEVICE = fr_io::FC_DEVICE, FC_LOOP_FILE = fr_io::FC_LOOP_FILE, FC_ZERO_FILE = fr_io::FC_ZERO_FILE, FC_FILE_COUNT = 3, // must be equal to count of preceding enum constants, FC_SECONDARY_STORAGE = fr_io::FC_SECONDARY_STORAGE, FC_ALL_FILE_COUNT = 4, FC_PRIMARY_STORAGE = fr_io::FC_PRIMARY_STORAGE, FC_STORAGE = fr_io::FC_STORAGE, FC_FREE_SPACE = fr_io::FC_FREE_SPACE, }; private: typedef fr_io super_type; /** direction of copy_bytes() operations */ enum fr_dir_posix { FC_POSIX_STORAGE2DEV, FC_POSIX_DEV2STORAGE, FC_POSIX_DEV2RAM, FC_POSIX_RAM2DEV, }; int fd[FC_ALL_FILE_COUNT]; void * storage_mmap, * buffer_mmap; ft_size storage_mmap_size, buffer_mmap_size; /* device major/minor numbers */ ft_dev this_dev_blkdev; /** open DEVICE */ int open_dev(const char * path); /** really open DEVICE */ int open_dev0(const char * path, int * ret_fd, ft_dev * ret_dev, ft_uoff * ret_len); /** open LOOP-FILE or ZERO-FILE */ int open_file(ft_size i, const char * path); /** set device major/minor numbers */ FT_INLINE void dev_blkdev(ft_dev blkdev) { this_dev_blkdev = blkdev; } protected: /** return true if a single descriptor/stream is open */ bool is_open0(ft_size which) const; /** close a single descriptor/stream */ void close0(ft_size which); /** return device major/minor numbers, or 0 if not known */ FT_INLINE ft_dev dev_blkdev() const { return this_dev_blkdev; } /** return true if this I/O has open descriptors/streams to LOOP-FILE and FREE-SPACE */ bool is_open_extents() const; /* return (-)EOVERFLOW if request from/to + length overflow specified maximum value */ static int validate(const char * type_name, ft_uoff type_max, fr_dir_posix dir, ft_uoff from, ft_uoff to, ft_uoff length); /** * retrieve LOOP-FILE extents and any additional extents to be ZEROED * and insert them into the vectors loop_file_extents, and to_zero_extents * the vectors will be ordered by extent ->logical (for to_zero_extents, ->physical and ->logical will be the same). * * return 0 for success, else error (and vectors contents will be UNDEFINED). * * if success, also update the parameter ret_effective_block_size_log2 to be the log2() * of device effective block size (see read_extents() for detailed meaning of this parameter) */ int read_extents_loop_file(fr_vector & loop_file_extents, fr_vector & to_zero_extents, ft_uoff & ret_block_size_bitmask); /** * retrieve FREE-SPACE extents and any additional extents to be ZEROED * and insert them into the vectors free_space_extents, and to_zero_extents * the vectors will be ordered by extent ->logical (for to_zero_extents, ->physical and ->logical will be the same). * * return 0 for success, else error (and vectors contents will be UNDEFINED). * * if success, also update the parameter ret_effective_block_size_log2 to be the log2() * of device effective block size (see read_extents() for detailed meaning of this parameter) */ int read_extents_free_space(const fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents, ft_uoff & ret_block_size_bitmask); /** * retrieve LOOP-FILE extents, FREE-SPACE extents and any additional extents to be ZEROED * and insert them into the vectors loop_file_extents, free_space_extents and to_zero_extents * the vectors will be ordered by extent ->logical (for to_zero_extents, ->physical and ->logical will be the same). * * return 0 for success, else error (and vectors contents will be UNDEFINED). * * if success, also update the parameter ret_effective_block_size_log2 to be the log2() * of device effective block size. * the device effective block size is defined as follows: * it is the largest power of 2 that exactly divides all physical, * logical and lengths in all returned extents (both for LOOP-FILE * and for FREE-SPACE) and that also exactly exactly divides device length. * * the trick fr_io_posix uses to implement this method * is to fill the device's free space with a ZERO-FILE, * and actually retrieve the extents used by ZERO-FILE. */ virtual int read_extents(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents, ft_uoff & ret_block_size_bitmask); /** * replace a part of the mmapped() storage_mmap area with specified storage_extent, * and store mmapped() address into storage_extent.user_data(). * return 0 if success, else error. * * note: fd shoud be this->fd[FC_DEVICE] for primary storage, * or this->fd[FC_SECONDARY_STORAGE] for secondary storage */ int replace_storage_mmap(int fd, const char * label, fr_extent & storage_extent, ft_size extent_index, ft_size & mem_offset); /** * create and open SECONDARY-STORAGE in job.job_dir() + '.storage.bin' * and fill it with 'secondary_len' bytes of zeros. do not mmap() it. * return 0 if success, else error */ int create_secondary_storage(ft_size secondary_len); /** * actually copy a list of fragments from DEVICE to STORAGE, or from STORAGE or DEVICE, or from DEVICE to DEVICE. * note: parameters are in bytes! * return 0 if success, else error. */ virtual int flush_copy_bytes(fr_dir dir, fr_vector & request_vec); /** internal method called by flush_copy_bytes() to read/write from DEVICE to mmapped() memory (either RAM or STORAGE) */ int flush_copy_bytes(fr_dir_posix dir2, const fr_extent & request); /** internal method called by flush_copy_bytes() to read/write from DEVICE to mmapped() memory (either RAM or STORAGE) */ int flush_copy_bytes(fr_dir_posix dir, ft_uoff from, ft_uoff to, ft_uoff length); /** * flush any I/O specific buffer * return 0 if success, else error * implementation: call msync() because we use a mmapped() buffer for copy() * and call sync() because we write() to DEVICE */ virtual int flush_bytes(); /** internal method, called by flush_bytes() to perform msync() on mmapped storage */ int msync_bytes(const fr_extent & extent) const; /** * write zeroes to device (or to storage). * used to remove device-renumbered blocks once remapping is finished */ virtual int zero_bytes(fr_to to, ft_uoff offset, ft_uoff length); public: /** constructor */ fr_io_posix(fr_persist & persist); /** destructor. calls close() */ virtual ~fr_io_posix(); /** check for consistency and open DEVICE, LOOP-FILE and ZERO-FILE */ virtual int open(const fr_args & args); /** return true if this fr_io_posix is currently (and correctly) open */ virtual bool is_open() const; /** close this I/O, including file descriptors to DEVICE, LOOP-FILE, ZERO-FILE and SECONDARY-STORAGE */ virtual void close(); /** * close the file descriptors for LOOP-FILE and ZERO-FILE */ virtual void close_extents(); /** * create and open SECONDARY-STORAGE in job.job_dir() + '.storage', * fill it with 'secondary_len' bytes of zeros and mmap() it. * * then mmap() together into consecutive RAM this->primary_storage extents and secondary_storage extents. * * return 0 if success, else error */ virtual int create_storage(ft_size secondary_len, ft_size mem_buffer_len); /** call umount(8) on dev_path() */ virtual int umount_dev(); /** * called once by work::relocate() immediately before starting the remapping phase. * * checks that last device block to be written is actually writable. * Reason: at least on Linux, if a filesystems is smaller than its containing device, it often limits to its length the writable blocks in the device. */ int check_last_block(); /** * write zeroes to primary storage. * used to remove primary-storage once remapping is finished * and clean the remaped file-system */ virtual int zero_primary_storage(); /** close and munmap() SECONDARY-STORAGE. called by close() and by work::close_storage() */ virtual int close_storage(); /** called to remove SECONDARY-STORAGE from file system if execution is completed successfully */ virtual int remove_storage_after_success(); }; FT_IO_NAMESPACE_END #endif /* FSREMAP_IO_IO_POSIX_HH */ fstransform-0.9.4/fsremap/src/io/io_posix_dir.cc000066400000000000000000000053701345021500300217170ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/io_posix_dir.cc * * Created on: Sep 22, 2011 * Author: max */ #include "../first.hh" #if defined(FT_HAVE_CERRNO) # include // for errno and error codes #elif defined(FT_HAVE_ERRNO_H) # include #endif #ifdef FT_HAVE_SYS_TYPES_H # include // for DIR, opendir() #endif #ifdef FT_HAVE_DIRENT_H # include // " " " , readdir(), closedir() #endif #include "../log.hh" // for ff_log() #include "io_posix_dir.hh" // for ft_io_posix_dir FT_IO_NAMESPACE_BEGIN /** default constructor */ ft_io_posix_dir::ft_io_posix_dir() : this_path(), this_dir(NULL) { } /** destructor. calls close() */ ft_io_posix_dir::~ft_io_posix_dir() { close(); } /** open a directory */ int ft_io_posix_dir::open(const ft_string & path) { int err = 0; if (this_dir != NULL) err = EISCONN; else if ((this_dir = opendir(path.c_str())) == NULL) err = errno; else { this_path = path; return err; } return ff_log(FC_ERROR, err, "failed to open directory `%s'", path.c_str()); } /** close the currently open directory */ int ft_io_posix_dir::close() { if (this_dir != NULL) { if (closedir(this_dir) != 0) return ff_log(FC_ERROR, errno, "failed to close directory `%s'", this_path.c_str()); this_dir = NULL; } this_path.clear(); return 0; } /** * get next directory entry. * returns 0 if success (NULL result indicates EOF), * else returns error code */ int ft_io_posix_dir::next(ft_io_posix_dirent * & result) { int err; if (this_dir == NULL) err = ENOTCONN; else { errno = 0; result = readdir(this_dir); if ((err = errno) == 0) // 0 for success or end-of-dir return err; } return ff_log(FC_ERROR, err, "failed to read directory `%s'", this_path.c_str()); } FT_IO_NAMESPACE_END fstransform-0.9.4/fsremap/src/io/io_posix_dir.hh000066400000000000000000000042461345021500300217320ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io_posix_dir.hh * * Created on: Sep 22, 2011 * Author: max */ #ifndef FSTRANSFORM_IO_IO_POSIX_DIR_HH #define FSTRANSFORM_IO_IO_POSIX_DIR_HH #include "../types.hh" // for ft_string, ft_inode #ifdef FT_HAVE_DIRENT_H # include // for DIR, DT_UNKNOWN #endif FT_IO_NAMESPACE_BEGIN typedef struct dirent ft_io_posix_dirent; class ft_io_posix_dir { private: ft_string this_path; DIR * this_dir; /** cannot call copy constructor */ ft_io_posix_dir(const ft_io_posix_dir &); /** cannot call assignment operator */ const ft_io_posix_dir & operator=(const ft_io_posix_dir &); public: /** default constructor */ ft_io_posix_dir(); /** destructor, calls close() */ ~ft_io_posix_dir(); /** open a directory */ int open(const ft_string & path); FT_INLINE bool is_open() const { return this_dir != NULL; }; FT_INLINE DIR * dir() { return this_dir; } FT_INLINE const ft_string & path() const { return this_path; } /** * get next directory entry. * returns 0 if success (NULL result indicates EOF), * else returns error code */ int next(ft_io_posix_dirent * & result); /** close the currently open directory */ int close(); }; FT_IO_NAMESPACE_END #endif /* FSTRANSFORM_IO_IO_POSIX_DIR_HH */ fstransform-0.9.4/fsremap/src/io/io_prealloc.cc000066400000000000000000000504241345021500300215200ustar00rootroot00000000000000/*q * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/io_posix.cc * * Created on: Feb 28, 2011 * Author: max */ #include "../first.hh" #if defined(FT_HAVE_ERRNO_H) # include // for errno #elif defined(FT_HAVE_CERRNO) # include // for errno #endif #if defined(FT_HAVE_STRING_H) # include // for strlen() #elif defined(FT_HAVE_CSTRING) # include // for strlen() #endif #ifdef FT_HAVE_SYS_TYPES_H # include // for open() #endif #ifdef FT_HAVE_SYS_STAT_H # include // for " #endif #ifdef FT_HAVE_FCNTL_H # include // for " #endif #ifdef FT_HAVE_UNISTD_H # include // for close() #endif #include "../log.hh" // for ff_log() #include "../misc.hh" // for ff_max2(), ff_min2() #include "../vector.hh" // for fr_vector #include "../cache/cache_mem.hh" // for ft_cache_mem #include "util_posix.hh" // for ff_posix_stat() #include "extent_posix.hh" // for ff_read_extents_posix() #include "io_prealloc.hh" // for fr_io_prealloc FT_IO_NAMESPACE_BEGIN const char * const fr_io_prealloc::MP_LABEL[] = { LABEL[FC_DEVICE], LABEL[FC_LOOP_FILE] }; /** constructor. */ fr_io_prealloc::fr_io_prealloc(fr_persist & persist) : super_type(persist), this_inode_cache(NULL), mount_point(), loop_file_path(), loop_dev_path(NULL), cmd_losetup(NULL) { // TODO: command-line option to use ft_cache_symlink_kv this_inode_cache = new ft_cache_mem(); } /** destructor. calls close() */ fr_io_prealloc::~fr_io_prealloc() { close(); delete this_inode_cache; this_inode_cache = NULL; } /** return true if device and loop file mount points are currently (and correctly) open */ bool fr_io_prealloc::is_open_dirs() const { for (ft_size i = 0; i < FC_MOUNT_POINTS_N; i++) if (!mount_point[i].is_open()) return false; return true; } /** return true if this fr_io_prealloc is currently (and correctly) open */ bool fr_io_prealloc::is_open() const { return super_type::is_open() && is_open_dirs(); } /** check for consistency and open DEVICE, LOOP-FILE and ZERO-FILE */ int fr_io_prealloc::open(const fr_args & args) { int err = super_type::open(args); if (err != 0) return err; const char * loop_file_path_cstr = args.io_args[FC_LOOP_FILE]; if (loop_file_path_cstr == NULL) { ff_log(FC_ERROR, 0, "option --io=prealloc requires arguments %s %s [%s]", LABEL[FC_DEVICE], LABEL[FC_LOOP_FILE], LABEL[FC_ZERO_FILE]); return -EINVAL; } this_inode_cache->clear(); loop_file_path = loop_file_path_cstr; loop_dev_path = args.loop_dev; cmd_losetup = args.cmd_losetup; if (!is_replaying()) do { const ft_size mp_i = FC_MOUNT_POINT_DEVICE, mp_j = FC_MOUNT_POINT_LOOP_FILE; const char * const * mount_point_dir = args.mount_points; if (loop_dev_path == NULL || mount_point_dir[mp_i] == NULL || mount_point_dir[mp_j] == NULL) { ff_log(FC_ERROR, 0, "option --io=prealloc requires the options --loop-device=LOOP-DEV, --device-mount-point=DIR and --loop-mount-point=DIR"); err = -EINVAL; break; } ft_size i, n = FC_MOUNT_POINTS_N; for (i = 0; i < n; i++) { ft_string path = mount_point_dir[i]; if ((err = mount_point[i].open(path)) != 0) break; } } while (0); if (err != 0) close(); return err; } /** * close this I/O, including device and loop file mount points. * Obviously calls super_type::close() */ void fr_io_prealloc::close() { this_inode_cache->clear(); ft_size i, n = FC_MOUNT_POINTS_N; for (i = 0; i < n; i++) { mount_point[i].close(); } loop_file_path.clear(); loop_dev_path = NULL; cmd_losetup = NULL; super_type::close(); } /** call umount(8) on loop_dev_path */ int fr_io_prealloc::cmd_umount_loop_dev() { const char * cmd = cmd_umount(), * dev = loop_dev_path; std::vector args; if (cmd == NULL) // posix standard name for umount(8) cmd = "/bin/umount"; args.push_back(cmd); // only one argument: device path args.push_back(dev); args.push_back(NULL); // needed by ff_posix_exec() as end-of-arguments marker ff_log(FC_INFO, 0, "unmounting %s '%s'... command: %s %s", label[FC_LOOP_FILE], dev, cmd, dev); int err = ff_posix_exec(args[0], & args[0]); if (err == 0) ff_log(FC_INFO, 0, "successfully unmounted %s '%s'", label[FC_LOOP_FILE], dev); return err; } /** call losetup(8) on loop_dev_path */ int fr_io_prealloc::cmd_losetup_loop_dev() { const char * cmd = cmd_losetup, * dev = loop_dev_path; std::vector args; if (cmd == NULL) // Linux standard name for losetup(8) cmd = "/sbin/losetup"; args.push_back(cmd); args.push_back("-d"); args.push_back(dev); args.push_back(NULL); // needed by ff_posix_exec() as end-of-arguments marker ff_log(FC_INFO, 0, "disconnecting %s '%s'... command: %s -d %s", label[FC_LOOP_FILE], dev, cmd, dev); int err = ff_posix_exec(args[0], & args[0]); if (err == 0) ff_log(FC_NOTICE, 0, "successfully disconnected %s '%s'", label[FC_LOOP_FILE], dev); return err; } /** call umount(8) and losetup(8) on loop_dev_path, then call umount(8) on dev_path() */ int fr_io_prealloc::umount_dev() { int err = 0; for (ft_size i = 0; i < FC_MOUNT_POINTS_N; i++) // we must close mount_point[] to allow unmounting device and loop_device if ((err = mount_point[i].close()) != 0) break; if (err == 0 && (err = cmd_umount_loop_dev()) == 0 && (err = cmd_losetup_loop_dev()) == 0 && (err = super_type::umount_dev()) == 0) { } return err; } /** * retrieve LOOP-FILE extents and FREE-SPACE extents and insert them into * the vectors loop_file_extents and free_space_extents. * the vectors will be ordered by extent ->logical. * * return 0 for success, else error (and vectors contents will be UNDEFINED). * * this implementation calls super_type::read_extents() to get the extents for LOOP FILE and (optionally) ZERO FILE, * then recursively scans the contents of device and loop file mount points * to match the actual extents from files inside device * with the preallocated extents from files inside loop file. * * This trick allows a significant speedup, as fsmove needs only to preallocate files inside loop file, not to actually move them */ int fr_io_prealloc::read_extents(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents, ft_uoff & ret_block_size_bitmask) { ft_uoff block_size_bitmask = ret_block_size_bitmask; int err = 0; do { if (!is_open_dirs()) { ff_log(FC_ERROR, 0, "unexpected call to fr_io_prealloc::read_extents(), I/O is not open"); err = -ENOTCONN; // not open! break; } err = read_extents_dir( mount_point[FC_MOUNT_POINT_DEVICE], mount_point[FC_MOUNT_POINT_LOOP_FILE].path(), loop_file_extents, to_zero_extents, block_size_bitmask); if (err != 0) break; fr_vector super_loop_file_extents; err = super_type::read_extents_loop_file(super_loop_file_extents, to_zero_extents, block_size_bitmask); if (err != 0) break; // fr_io_posix::read_extents_loop_file() may add to its loop_file_extents // some extents that overlap with the ones computed above. // remove any such overlap! if (!loop_file_extents.empty() && !super_loop_file_extents.empty()) { ff_log(FC_DEBUG, 0, "merging %" FT_ULL " prealloc extents with %" FT_ULL " %s extents", (ft_ull) loop_file_extents.size(), (ft_ull) super_loop_file_extents.size(), LABEL[FC_LOOP_FILE]); const ft_uoff eff_block_size_log2 = effective_block_size_log2(block_size_bitmask); const ft_uoff eff_block_size = (ft_uoff)1 << eff_block_size_log2; loop_file_extents.show("prealloc", " before merge", eff_block_size); super_loop_file_extents.show(LABEL[FC_LOOP_FILE], " before merge", eff_block_size); // use fr_map::merge_shift() to merge. // unluckily it merges based on ->physical, so we must transpose the vectors loop_file_extents.transpose(); super_loop_file_extents.transpose(); fr_map map; enum { NO_SHIFT = 0 }; map.append0_shift(loop_file_extents, NO_SHIFT); map.merge_shift(super_loop_file_extents, NO_SHIFT, FC_PHYSICAL1); loop_file_extents.assign(map.begin(), map.end()); loop_file_extents.transpose(); // loop_file_extents is now sorted by logical, // because fr_map is intrinsically sorted by physical ff_log(FC_DEBUG, 0, "merge completed, result is %" FT_ULL " extents", (ft_ull) loop_file_extents.size()); loop_file_extents.show(LABEL[FC_LOOP_FILE], " after merge", eff_block_size); } // we must call super_type::read_extents_free_space() after preparing loop_file_extents because, // if ZERO-FILE is not specified, it will use loop_file_extents // (assuming it is sorted by ->logical) and compute free_space_extents as its complement err = super_type::read_extents_free_space(loop_file_extents, free_space_extents, to_zero_extents, block_size_bitmask); if (err != 0) break; // no guarantee to_zero_extents is already sorted, so we have to sort it before returning to_zero_extents.sort_by_logical(); ret_block_size_bitmask = block_size_bitmask; } while (0); return err; } /** return true if 'stat' information is about a directory */ FT_INLINE static bool fr_io_posix_is_dir(const ft_stat & stat) { return S_ISDIR(stat.st_mode); } /** return true if 'stat' information is about a regular file */ FT_INLINE static bool fr_io_posix_is_file(const ft_stat & stat) { return S_ISREG(stat.st_mode); } /** return file type textual description */ FT_INLINE static const char * fr_io_posix_get_type(const ft_stat & stat) { if (S_ISDIR(stat.st_mode)) return "directory"; if (S_ISREG(stat.st_mode)) return "file"; if (S_ISLNK(stat.st_mode)) return "symlink"; if (S_ISCHR(stat.st_mode)) return "character-device"; if (S_ISBLK(stat.st_mode)) return "block-device"; if (S_ISFIFO(stat.st_mode)) return "fifo"; if (S_ISSOCK(stat.st_mode)) return "socket"; return "unknown"; } #define FC_INVALID_FS_STR "invalid preallocated loop file system" /** * check if inode is a hard link to an already examined file or special device, * and in case return true, otherwise return EAGAIN. * * do NOT call this method if inode is a directory! * * return -errno in case of errors. */ int fr_io_prealloc::hard_link(const char * src_path, const ft_stat & src_stat, const char * dst_path, const ft_stat & dst_stat) { if (S_ISDIR(src_stat.st_mode)) { ff_log(FC_FATAL, 0, "internal error, io_prealloc::hard_link(%s, ...) invoked on a directory!", src_path); return -EISDIR; } if (S_ISDIR(dst_stat.st_mode)) { ff_log(FC_FATAL, 0, "internal error, io_prealloc::hard_link(..., %s) invoked on a directory!", dst_path); return -EISDIR; } const ft_nlink src_nlink = src_stat.st_nlink, dst_nlink = dst_stat.st_nlink; if (src_nlink != dst_nlink) { ff_log(FC_ERROR, 0, "%s: '%s' has %" FT_ULL " link%s, while '%s' has %" FT_ULL " link%s", FC_INVALID_FS_STR, src_path, (ft_ull) src_nlink, src_nlink == 1 ? "" : "s", dst_path, (ft_ull) dst_nlink, dst_nlink == 1 ? "" : "s"); return -EINVAL; } if (dst_nlink <= 1) // at most one link, cannot be in inode_cache return EAGAIN; /* * source inode has 2 or more links. * check if it is cached already, or add it to detect further links to the same file/device */ const ft_inode dst_inode = dst_stat.st_ino; // (dst_nlink - 1) because we just found one link to this inode: // we expect to find (dst_nlink - 1) other links ft_nlink cached_nlink = dst_nlink - 1; int err = this_inode_cache->find_or_add(dst_inode, cached_nlink); if (err < 0) return err; if (err == 0) { // fake error to tell caller that inode was not in inode_cache return EAGAIN; } if (cached_nlink == 1) { // we do not expect further links to this inode return this_inode_cache->find_and_delete(dst_inode, cached_nlink); } // we expect further links to this inode return this_inode_cache->find_and_update(dst_inode, cached_nlink - 1); } /** * recursively scan the contents of src and dst directories * to match the actual extents from files inside device (src) * with the preallocated extents from files inside loop file (dst). * * any preallocated extents in files inside loop file * which do NOT have a correspondence in files inside device * are added to to_zero_extents. * * NOTE: loop_file_extents will be filled with UNSORTED data */ int fr_io_prealloc::read_extents_dir(ft_io_posix_dir & src, const ft_string & dst, fr_vector & loop_file_extents, fr_vector & to_zero_extents, ft_uoff & ret_block_size_bitmask) { ft_string src_file = src.path(); src_file += '/'; ft_string dst_file = dst; dst_file += '/'; ft_stat src_stat, dst_stat; ft_uoff block_size_bitmask = ret_block_size_bitmask; ft_io_posix_dirent * entry; const char * name; ft_size namelen; int err; /* recurse on directory contents */ while ((err = src.next(entry)) == 0 && entry != NULL) { namelen = strlen(name = entry->d_name); // skip "." and ".." if ((namelen == 1 || namelen == 2) && !memcmp(name, "..", namelen)) continue; src_file.resize(src.path().size() + 1); // truncate to src + '/' src_file.append(name, namelen); const char * src_path = src_file.c_str(); if (src_file == loop_file_path) // skip loop file itself! continue; dst_file.resize(dst.size() + 1); // truncate to dst + '/' dst_file.append(name, namelen); const char * dst_path = dst_file.c_str(); if ((err = ff_posix_stat(src_path, & src_stat)) != 0) { break; } if ((err = ff_posix_stat(dst_path, & dst_stat)) != 0) { break; } const char * src_type = fr_io_posix_get_type(src_stat); const char * dst_type = fr_io_posix_get_type(dst_stat); if (src_type != dst_type) { ff_log(FC_ERROR, 0, "%s: '%s' is a %s, while '%s' is a %s", FC_INVALID_FS_STR, src_path, src_type, dst_path, dst_type); err = -EINVAL; break; } if (fr_io_posix_is_dir(src_stat)) { ft_io_posix_dir src_dir; if ((err = src_dir.open(src_file)) == 0) { err = read_extents_dir(src_dir, dst_file, loop_file_extents, to_zero_extents, block_size_bitmask); // no need, src_dir destructor calls close() // src_dir.close(); } continue; } if ((err = hard_link(src_path, src_stat, dst_path, dst_stat)) == 0) { // no need to examine the file or special device: // it is a hard link to an already examined one continue; } else if (err == EAGAIN) { /* no luck with inode_cache, proceed as usual */ err = 0; } else { /** hard link() failed */ break; } if (fr_io_posix_is_file(src_stat)) { err = read_extents_file(src_path, src_stat, dst_path, dst_stat, loop_file_extents, to_zero_extents, block_size_bitmask); } } if (err == 0) ret_block_size_bitmask = block_size_bitmask; return err; } /** * match the actual extents from (src_path) file inside device * with the preallocated extents from (dst_path) file inside loop file. * * any preallocated extents in files inside loop file * which do NOT have a correspondence in files inside device * are added to to_zero_extents */ int fr_io_prealloc::read_extents_file(const char * src_path, const ft_stat & src_stat, const char * dst_path, const ft_stat & dst_stat, fr_vector & loop_file_extents, fr_vector & to_zero_extents, ft_uoff & ret_block_size_bitmask) { ft_uoff block_size_bitmask = ret_block_size_bitmask; int err = 0; do { enum { SRC = 0, DST = 1, N = 2 }; ft_uoff len[N] = { (ft_uoff) src_stat.st_size, (ft_uoff) dst_stat.st_size }; if (len[SRC] != len[DST]) { ff_log(FC_ERROR, 0, "%s: file '%s' is %" FT_ULL " bytes, while file '%s' is %" FT_ULL " bytes", FC_INVALID_FS_STR, src_path, (ft_ull) len[SRC], dst_path, (ft_ull) len[DST]); err = -EINVAL; break; } if (len[SRC] == 0) break; fr_vector extent[N]; const char * const path[N] = { src_path, dst_path }; // loop on { SRC, DST } for (ft_size i = 0; err == 0 && i < N; i++) { int fd; if ((fd = ::open(path[i], O_RDONLY)) < 0) { err = ff_log(FC_ERROR, errno, "error opening file '%s' inside %s", path[i], MP_LABEL[i]); break; } err = ff_read_extents_posix(fd, len[i], extent[i], block_size_bitmask); if (::close(fd) < 0) ff_log(FC_WARN, errno, "failed to close file '%s' inside %s", path[i], MP_LABEL[i]); } if (err != 0) break; fr_vector unmapped; // PROBLEM: dst file-system may have a smaller blocksize than src file-system // Consequence: extent[SRC] may have an 'unnecessary' tail fragment that cannot be mapped to dst // SOLUTION: explicitly check for this case and manually remove such tail if (!extent[SRC].empty() && !extent[DST].empty()) { fr_extent & e1 = extent[SRC].back(), & e2 = extent[DST].back(); ft_uoff end1 = e1.logical() + e1.length(); ft_uoff end2 = e2.logical() + e2.length(); if (end1 > end2 && end2 >= len[SRC]) extent[SRC].truncate_at_logical(end2); } if ((err = loop_file_extents.compose(extent[SRC], extent[DST], block_size_bitmask, unmapped)) != 0) break; for (ft_size i = 0, n = unmapped.size(); i < n; i++) { const fr_extent & e = unmapped[i]; // to_zero_extents must have ->physical == ->logical // and in any case the ->logical extents are relative to each file, // so they cannot be mixed together to_zero_extents.append(e.physical(), e.physical(), e.length(), e.user_data()); } ret_block_size_bitmask = block_size_bitmask; } while (0); return err; } FT_IO_NAMESPACE_END fstransform-0.9.4/fsremap/src/io/io_prealloc.hh000066400000000000000000000134071345021500300215320ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/io_prealloc.hh * * Created on: Apr 18, 2012 * Author: max */ #ifndef FSREMAP_IO_IO_PREALLOC_HH #define FSREMAP_IO_IO_PREALLOC_HH #include "../args.hh" // for FC_MOUNT_POINT* #include "../types.hh" // for ft_uoff #include "../cache/cache.hh" // for ft_cache #include "io_posix.hh" // for fr_io_posix #include "io_posix_dir.hh" // for ft_io_posix_dir FT_IO_NAMESPACE_BEGIN /** * class performing I/O on POSIX systems with preallocation */ class fr_io_prealloc: public fr_io_posix { private: typedef fr_io_posix super_type; static const char * const MP_LABEL[FC_MOUNT_POINTS_N]; // inode-cache. used to examine only once multiple links to the same file ft_cache * this_inode_cache; // device and loop mount points ft_io_posix_dir mount_point[FC_MOUNT_POINTS_N]; // loop device path ft_string loop_file_path; // loop device path const char * loop_dev_path; // 'losetup' command to disconnect loop device const char * cmd_losetup; /** call umount(8) on loop_dev_path */ int cmd_umount_loop_dev(); /** call losetup(8) on loop_dev_path */ int cmd_losetup_loop_dev(); /** * check if inode is a hard link to an already examined file or special device, * and in case return true, otherwise return EAGAIN. * * do NOT call this method if inode is a directory! * * return -errno in case of errors. */ int hard_link(const char * src_path, const ft_stat & src_stat, const char * dst_path, const ft_stat & dst_stat); /** * recursively scan the contents of src and dst directories * to match the actual extents from files inside device (src) * with the preallocated extents from files inside loop file (dst). * * any preallocated extents in files inside loop file * which do NOT have a correspondence in files inside device * are added to to_zero_extents. * * NOTE: loop_file_extents will be filled with UNSORTED data */ int read_extents_dir(ft_io_posix_dir & src, const ft_string & dst, fr_vector & loop_file_extents, fr_vector & to_zero_extents, ft_uoff & ret_block_size_bitmask); /** * match the actual extents from (src_path) file inside device * with the preallocated extents from (dst_path) file inside loop file. * * any preallocated extents in files inside loop file * which do NOT have a correspondence in files inside device * are added to to_zero_extents */ int read_extents_file(const char * src_path, const ft_stat & src_stat, const char * dst_path, const ft_stat & dst_stat, fr_vector & loop_file_extents, fr_vector & to_zero_extents, ft_uoff & ret_block_size_bitmask); protected: /** return true if device and loop file mount points are currently (and correctly) open */ bool is_open_dirs() const; /** * retrieve LOOP-FILE extents and FREE-SPACE extents and insert them into * the vectors loop_file_extents and free_space_extents. * the vectors will be ordered by extent ->logical. * * return 0 for success, else error (and vectors contents will be UNDEFINED). * * if success, also returns in ret_effective_block_size_log2 the log2() * of device effective block size. * the device effective block size is defined as follows: * it is the largest power of 2 that exactly divides all physical, * logical and lengths in all returned extents (both for LOOP-FILE * and for FREE-SPACE) and that also exactly exactly divides device length. * * the trick fr_io_posix uses to implement this method * is to fill the device's free space with a ZERO-FILE, * and actually retrieve the extents used by ZERO-FILE. */ virtual int read_extents(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents, ft_uoff & ret_block_size_bitmask); public: /** constructor. */ fr_io_prealloc(fr_persist & persist); /** destructor. calls close() */ virtual ~fr_io_prealloc(); /** check for consistency and open DEVICE, LOOP-FILE and ZERO-FILE */ virtual int open(const fr_args & args); /** return true if this fr_io_prealloc is currently (and correctly) open */ virtual bool is_open() const; /** call umount(8) and losetup(8) on loop_dev_path, then call umount(8) on dev_path() */ virtual int umount_dev(); /** * close this I/O, including device and loop file mount points. * Obviously calls super_type::close() */ virtual void close(); }; FT_IO_NAMESPACE_END #endif /* FSREMAP_IO_IO_PREALLOC_HH */ fstransform-0.9.4/fsremap/src/io/io_self_test.cc000066400000000000000000000153461345021500300217130ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/io_self_test.cc * * Created on: Mar 23, 2011 * Author: max */ #include "../first.hh" #include "../log.hh" // for ff_log() #include "../misc.hh" // for ff_min2(), ff_max2(), ff_random() #include "io_self_test.hh" // for fr_io_self_test FT_IO_NAMESPACE_BEGIN /** constructor */ fr_io_self_test::fr_io_self_test(fr_persist & persist) : super_type(persist), this_block_size_log2(0) { } /** destructor. calls close() */ fr_io_self_test::~fr_io_self_test() { close(); } /** return true if this fr_io_self_test is currently (and correctly) open */ bool fr_io_self_test::is_open() const { return dev_length() != 0; } /** check for consistency and load LOOP-FILE and ZERO-FILE extents list from files */ int fr_io_self_test::open(const fr_args & args) { if (is_open()) { // already open! ff_log(FC_ERROR, 0, "unexpected call, I/O is already open"); return -EISCONN; } if (is_replaying()) { ff_log(FC_ERROR, 0, "resuming job is meaningless for self-test I/O"); return -EINVAL; } int err = fr_io::open(args); if (err != 0) return err; /* * block_size_log_2 is a random number in the range [8,16] * thus block_size is one of 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 */ this_block_size_log2 = (ft_uoff) ff_random(8) + 8; /* dev_len is a random number in the range [block_size, 1TB * block_size] */ ft_uoff dev_len_shift = (ft_uoff) ff_random(20); ft_uoff dev_len = (1 + ff_random((ft_ull)1047576)) << (this_block_size_log2 + dev_len_shift); dev_length(dev_len); loop_file_length(dev_len); dev_path(""); double pretty_len; const char * pretty_label = ff_pretty_size(dev_len, & pretty_len); ff_log(FC_INFO, 0, "%s%s length is %.2f %sbytes", sim_msg, label[FC_DEVICE], pretty_len, pretty_label); return err; } /** close this I/O, including file descriptors to DEVICE, LOOP-FILE and ZERO-FILE */ void fr_io_self_test::close() { this_block_size_log2 = 0; super_type::close(); } /** close any resource associated to LOOP-FILE and ZERO-FILE extents */ void fr_io_self_test::close_extents() { } /** * retrieve LOOP-FILE extents and FREE-SPACE extents and append them into * the vectors loop_file_extents and free_space_extents. * the vectors will be ordered by extent ->logical. * * return 0 for success, else error (and vectors contents will be UNDEFINED). * * implementation: load extents list from files * (for example they could be the job persistence files) */ int fr_io_self_test::read_extents(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & FT_ARG_UNUSED(to_zero_extents), ft_uoff & ret_block_size_bitmask) { if (!is_open()) return ENOTCONN; // not open! ft_uoff dev_len = dev_length(), free_len = ff_random(dev_len >> this_block_size_log2) << this_block_size_log2; fr_map loop_file_map, free_space_map; invent_extents(loop_file_map, dev_len, ret_block_size_bitmask); invent_extents(free_space_map, free_len, ret_block_size_bitmask); /* remove from FREE-SPACE any extent->physical already present in LOOP-FILE */ fr_map intersect_map; intersect_map.intersect_all_all(loop_file_map, free_space_map, FC_PHYSICAL2); free_space_map.remove_all(intersect_map); loop_file_extents.insert(loop_file_extents.end(), loop_file_map.begin(), loop_file_map.end()); loop_file_extents.sort_by_logical(); free_space_extents.insert(free_space_extents.end(), free_space_map.begin(), free_space_map.end()); free_space_extents.sort_by_logical(); return 0; } /** fill ret_extents with random (but consistent) extents. extents will stop at 'file_len' bytes */ void fr_io_self_test::invent_extents(fr_map & extent_map, ft_uoff file_len, ft_uoff & ret_block_size_bitmask) const { fr_vector extent_vec; file_len >>= this_block_size_log2; ft_uoff pos = 0, hole, len, max_extent_len = ff_max2(file_len >> 16, (ft_uoff)0x100); fr_extent extent; while (pos < file_len) { /* make some holes in physical layout */ hole = ff_random(ff_min2(max_extent_len >> 4, file_len - pos - 1)); len = 1 + ff_min2((ft_uoff)ff_random(max_extent_len), file_len - pos - hole - 1); // length == 0 is not valid! ret_block_size_bitmask |= extent.physical() = (pos + hole) << this_block_size_log2; extent.logical() = 0; ret_block_size_bitmask |= extent.length() = len << this_block_size_log2; /* on average, one extent in 1024 is FC_EXTENT_ZEROED */ extent.user_data() = ff_random(1023) == 0 ? FC_EXTENT_ZEROED : FC_DEFAULT_USER_DATA; extent_vec.push_back(extent); pos += hole + len; } /* shuffle the extents list and set ->logical */ ft_size i, r, n = extent_vec.size(); pos = 0; for (i = 0; i + 1 < n; i++) { r = ff_random(n - i - 1); if (r != 0) std::swap(extent_vec[i], extent_vec[i + r]); fr_extent & extent_i = extent_vec[i]; /* also make some holes in logical layout */ if ((pos += ff_random(ff_min2(max_extent_len, file_len - pos) >> 8)) >= file_len) break; ret_block_size_bitmask |= extent_i.logical() = pos << this_block_size_log2; pos += extent_i.length() >> this_block_size_log2; extent_map.insert(extent_i); } if (i + 1 == n) { if ((pos += ff_random(ff_min2(max_extent_len, file_len - pos) >> 8)) < file_len) { fr_extent & extent_i = extent_vec[i]; ret_block_size_bitmask |= extent_i.logical() = pos << this_block_size_log2; pos += extent_i.length() >> this_block_size_log2; extent_map.insert(extent_i); } } } FT_IO_NAMESPACE_END fstransform-0.9.4/fsremap/src/io/io_self_test.hh000066400000000000000000000060011345021500300217110ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/io_self_test.hh * * Created on: Feb 23, 2011 * Author: max */ #ifndef FSREMAP_IO_IO_SELF_TEST_HH #define FSREMAP_IO_IO_SELF_TEST_HH #include "../types.hh" // for ft_uoff, ft_ull #include "io_null.hh" // for ft_io_null FT_IO_NAMESPACE_BEGIN /** * self-test class: * reports random LOOP-FILE and ZERO-FILE extents and emulates I/O */ class fr_io_self_test: public ft_io_null { private: typedef ft_io_null super_type; ft_ull this_block_size_log2; /** fill ret_extents with random (but consistent) extents. extents will stop at 'length' bytes */ void invent_extents(fr_map & ret_extents, ft_uoff length, ft_uoff & ret_block_size_bitmask) const; protected: /** * retrieve LOOP-FILE extents and FREE-SPACE extents and insert them into * the vectors loop_file_extents and free_space_extents. * the vectors will be ordered by extent ->logical. * * return 0 for success, else error (and vectors contents will be UNDEFINED). * * if success, also returns in ret_effective_block_size_log2 the log2() * of device effective block size. * * implementation: fill loop_file_extents and free_space_extents * with random (but consistent) data. */ virtual int read_extents(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents, ft_uoff & ret_block_size_bitmask); public: /** constructor */ fr_io_self_test(fr_persist & persist); /** destructor. calls close() */ virtual ~fr_io_self_test(); /** check for consistency and prepare for read_extents() */ virtual int open(const fr_args & args); /** return true if this fr_io_posix is currently (and correctly) open */ virtual bool is_open() const; /** close this I/O, including file descriptors to DEVICE, LOOP-FILE and ZERO-FILE */ virtual void close(); /** close any resource associated to LOOP-FILE and ZERO-FILE extents */ virtual void close_extents(); }; FT_IO_NAMESPACE_END #endif /* FSREMAP_IO_IO_SELF_TEST_HH */ fstransform-0.9.4/fsremap/src/io/io_test.cc000066400000000000000000000133761345021500300207030ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/io_test.cc * * Created on: Mar 4, 2011 * Author: max */ #include "../first.hh" #if defined(FT_HAVE_ERRNO_H) # include // for errno, EISCONN, ENOTCONN #elif defined(FT_HAVE_CERRNO) # include // for errno, EISCONN, ENOTCONN #endif #include "../log.hh" // for ff_log() #include "../args.hh" // for fr_args #include "../misc.hh" // for ff_str2un_scaled() #include "extent_file.hh" // for ff_read_extents_file() #include "io_test.hh" // for fr_io_test FT_IO_NAMESPACE_BEGIN /** constructor */ fr_io_test::fr_io_test(fr_persist & persist) : super_type(persist) { /* mark this_f[] as invalid: they are not open yet */ for (ft_size i = 0; i < FC_EXTENTS_FILE_COUNT; i++) this_f[i] = NULL; } /** destructor. calls close() */ fr_io_test::~fr_io_test() { close(); } /** return true if this fr_io_test is currently (and correctly) open */ bool fr_io_test::is_open() const { return dev_length() != 0; } /** check for consistency and load LOOP-FILE and ZERO-FILE extents list from files */ int fr_io_test::open(const fr_args & args) { if (is_open()) { // already open! ff_log(FC_ERROR, 0, "unexpected call to io_test::open(), I/O is already open"); return EISCONN; } int err = fr_io::open(args); if (err != 0) return err; char const* const* io_args = args.io_args; ft_uoff dev_len; ft_size i = FC_DEVICE_LENGTH; err = ff_str2un_scaled(io_args[i], & dev_len); if (err != 0) { return ff_log(FC_ERROR, errno, "error parsing %s '%s'", extents_label[i], io_args[i]); } if (!is_replaying()) { for (i = FC_DEVICE_LENGTH+1; i < FC_EXTENTS_FILE_COUNT; i++) { if ((this_f[i] = fopen(io_args[i], "r")) == NULL) { err = ff_log(FC_ERROR, errno, "error opening %s '%s'", extents_label[i], io_args[i]); break; } } } if (err == 0) { dev_length(dev_len); dev_path(""); } else close(); return err; } /** close a single descriptor/stream */ void fr_io_test::close0(ft_size i) { if (this_f[i] != NULL) { if (fclose(this_f[i]) != 0) ff_log(FC_WARN, errno, "warning: failed to close %s", extents_label[i]); this_f[i] = NULL; } } /** * close file descriptors. * return 0 for success, 1 for error (prints by itself error message to stderr) */ void fr_io_test::close() { close_extents(); super_type::close(); } /** * close the file descriptors for LOOP-FILE and ZERO-FILE */ void fr_io_test::close_extents() { for (ft_size i = 0; i < FC_EXTENTS_FILE_COUNT; i++) close0(i); } /** return true if this I/O has open descriptors/streams to LOOP-FILE and FREE-SPACE */ bool fr_io_test::is_open_extents() const { ft_size i, n = FC_EXTENTS_FILE_COUNT; for (i = FC_DEVICE_LENGTH+1; i < n; i++) if (this_f[i] == NULL) break; return i == n; } /** * retrieve LOOP-FILE extents, FREE-SPACE extents and any additional extents to be ZEROED * and insert them into the vectors loop_file_extents, free_space_extents and to_zero_extents * the vectors will be ordered by extent ->logical (for to_zero_extents, ->physical and ->logical will be the same). * * return 0 for success, else error (and vectors contents will be UNDEFINED). * * if success, also returns in ret_effective_block_size_log2 the log2() * of device effective block size. * the device effective block size is defined as follows: * it is the largest power of 2 that exactly divides all physical, * logical and lengths in all returned extents (both for LOOP-FILE * and for FREE-SPACE) and that also exactly exactly divides device length. * * this implementation simply reads extents from persistence files. */ int fr_io_test::read_extents(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents, ft_uoff & ret_block_size_bitmask) { ft_uoff block_size_bitmask = ret_block_size_bitmask; int err = 0; do { if (!is_open_extents()) { ff_log(FC_ERROR, 0, "unexpected call to io_test::read_extents(), I/O is not open"); err = -ENOTCONN; // not open! break; } fr_vector * ret_extents[FC_EXTENTS_FILE_COUNT] = { & loop_file_extents, & free_space_extents, & to_zero_extents, }; for (ft_size i = FC_LOOP_EXTENTS; i < FC_EXTENTS_FILE_COUNT; i++) { /* ff_load_extents_file() appends to fr_vector, does NOT overwrite it */ if ((err = ff_load_extents_file(this_f[i], * ret_extents[i], block_size_bitmask)) != 0) { err = ff_log(FC_ERROR, err, "error reading %s extents from save-file", extents_label[i]); break; } } } while (0); if (err == 0) ret_block_size_bitmask = block_size_bitmask; return err; } FT_IO_NAMESPACE_END fstransform-0.9.4/fsremap/src/io/io_test.hh000066400000000000000000000071311345021500300207050ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/io_test.hh * * Created on: Feb 28, 2011 * Author: max */ #ifndef FSREMAP_IO_IO_TEST_HH #define FSREMAP_IO_IO_TEST_HH #include "../types.hh" // for ft_uoff, ft_size #if defined(FT_HAVE_STDIO_H) # include // for FILE. also for fopen(), fclose() used in io_test.cc #elif defined(FT_HAVE_CSTDIO) # include // for FILE. also for fopen(), fclose() used in io_test.cc #endif #include "io_null.hh" // for ft_io_null FT_IO_NAMESPACE_BEGIN /** * "test" class emulating I/O. * actually loads extents definition from persistence files */ class fr_io_test: public ft_io_null { private: typedef ft_io_null super_type; FILE * this_f[FC_EXTENTS_FILE_COUNT]; protected: /** return true if this I/O has open descriptors/streams to LOOP-FILE and FREE-SPACE */ bool is_open_extents() const; /** close a single descriptor/stream */ void close0(ft_size which); /** * retrieve LOOP-FILE extents, FREE-SPACE extents and any additional extents to be ZEROED * and insert them into the vectors loop_file_extents, free_space_extents and to_zero_extents * the vectors will be ordered by extent ->logical (for to_zero_extents, ->physical and ->logical will be the same). * * return 0 for success, else error (and vectors contents will be UNDEFINED). * * if success, also returns in ret_effective_block_size_log2 the log2() * of device effective block size. * the device effective block size is defined as follows: * it is the largest power of 2 that exactly divides all physical, * logical and lengths in all returned extents (both for LOOP-FILE * and for FREE-SPACE) and that also exactly exactly divides device length. * * this implementation simply reads extents from persistence files. */ virtual int read_extents(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents, ft_uoff & ret_block_size_bitmask); public: /** constructor */ fr_io_test(fr_persist & persist); /** destructor. calls close() */ virtual ~fr_io_test(); /** check for consistency and load LOOP-FILE and ZERO-FILE extents list from files */ virtual int open(const fr_args & args); /** return true if this fr_io_posix is currently (and correctly) open */ virtual bool is_open() const; /** close this I/O, including file descriptors to DEVICE, LOOP-FILE and ZERO-FILE */ virtual void close(); /** * close the file descriptors for LOOP-FILE and ZERO-FILE */ virtual void close_extents(); }; FT_IO_NAMESPACE_END #endif /* FSREMAP_IO_IO_TEST_HH */ fstransform-0.9.4/fsremap/src/io/persist.cc000066400000000000000000000235511345021500300207220ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/persist.cc * * Created on: Mar 6, 2011 * Author: max */ #include "../first.hh" #if defined(FT_HAVE_ERRNO_H) # include // for errno, EISCONN, ENOTCONN #elif defined(FT_HAVE_CERRNO) # include // for errno, EISCONN, ENOTCONN #endif #if defined(FT_HAVE_STRING_H) # include // for strlen(), strcmp() #elif defined(FT_HAVE_CSTRING) # include // for strlen(), strcmp() #endif #include "../args.hh" // for FC_PRIMARY_STORAGE_EXACT_SIZE, FC_SECONDARY_STORAGE_EXACT_SIZE #include "../log.hh" // for ff_log() #include "persist.hh" // for fr_persist FT_IO_NAMESPACE_BEGIN /** constructor */ fr_persist::fr_persist(fr_job & job) : this_progress1((ft_ull)-1), this_progress2((ft_ull)-1), this_persist_path(), this_persist_file(NULL), this_job(job), this_replaying(false) { } #define FC_PERSIST_FILE_VERSION "version 0.9.4" #define FC_PERSIST_HEADER_SIMULATED "simulated job, " FC_PERSIST_FILE_VERSION #define FC_PERSIST_HEADER_REAL "real job, " FC_PERSIST_FILE_VERSION #define FC_OLD_HEADER_SIMULATED "simulated job" #define FC_OLD_HEADER_REAL "real job" /** create and open persistence file job.job_dir() + "/fsremap.persist" */ int fr_persist::open() { if (this_persist_file != NULL) { ff_log(FC_ERROR, 0, "unexpected call to open(), persistence is already initialized"); // return error as already reported return -EISCONN; } this_persist_path = this_job.job_dir(); this_persist_path += "/fsremap.persist"; const char * persist_path = this_persist_path.c_str(); // fopen(... "a+") = Open for reading and appending. The file is created if it does not exist. // The initial file position for reading is at the beginning of the file, // but output is always appended to the end of the file if ((this_persist_file = fopen(persist_path, "a+")) == NULL) return ff_log(FC_ERROR, errno, "failed to open persistence file '%s'", persist_path); this_replaying = this_job.resuming_job(); const bool simulated = this_job.simulate_run(); const char * header = simulated ? FC_PERSIST_HEADER_SIMULATED : FC_PERSIST_HEADER_REAL; const char * other_header = simulated ? FC_PERSIST_HEADER_REAL : FC_PERSIST_HEADER_SIMULATED; const char * header_old = simulated ? FC_OLD_HEADER_SIMULATED : FC_OLD_HEADER_REAL; const char * other_header_old = simulated ? FC_OLD_HEADER_REAL : FC_OLD_HEADER_SIMULATED; int err = 0; if (this_replaying) { enum { FT_LINE_LEN = 80 }; char line[FT_LINE_LEN + 1] = { '\0' }; if (fgets(line, FT_LINE_LEN, this_persist_file) == NULL) err = ff_log(FC_ERROR, errno, "I/O error reading from persistence file '%s'", this_persist_path.c_str()); else { // paranoia line[FT_LINE_LEN] = '\0'; ft_size line_len = strlen(line); // remove final '\n' if present if (line_len && line[line_len - 1] == '\n') line[--line_len] = '\0'; if (!strcmp(header, line) || !strcmp(header_old, line)) { err = do_read(this_progress1, this_progress2); } else if (!strcmp(other_header, line) || !strcmp(other_header_old, line)) { ff_log(FC_ERROR, 0, "tried to resume a %s: you MUST%s specify option '-n'%s", other_header, simulated ? " NOT" : "", simulated ? "" : " to simulate again"); err = -EINVAL; } else { ff_log(FC_ERROR, 0, "unsupported or corrupted persistence file '%s': expected header '%s', found '%s'", persist_path, header, line); err = -EINVAL; } } } else { if (fprintf(this_persist_file, "%s\n", header) < 0) err = ff_log(FC_ERROR, errno, "I/O error writing to persistence file '%s'", this_persist_path.c_str()); else err = do_flush(); } return err; } /** * get exact primary/secondary storage sizes. * also verify that sizes in persistence file (if present) match ones from command line (if specified). * if no exact sizes are available, sets them to 0. */ int fr_persist::get_storage_sizes_exact(ft_size & size1, ft_size & size2) { const ft_size job_size1 = this_job.job_storage_size(FC_PRIMARY_STORAGE_EXACT_SIZE); const ft_size job_size2 = this_job.job_storage_size(FC_SECONDARY_STORAGE_EXACT_SIZE); if (!this_replaying) { size1 = job_size1; size2 = job_size2; return 0; } // compare job_{primary,secondary}_size with the ones in persistence (if present) ft_ull persist_size1 = 0, persist_size2 = 0; int err = read(persist_size1, persist_size2); if (err != 0) return err; if (persist_size1 != 0 && job_size1 != 0 && persist_size1 != (ft_ull) job_size1) { ff_log(FC_ERROR, 0, "mismatched primary storage exact size: %" FT_ULL " bytes requested from command line, %" FT_ULL " bytes found in persistence file", (ft_ull) job_size1, persist_size1); err = -EINVAL; } if (persist_size2 != 0 && job_size2 != 0 && persist_size2 != (ft_ull) job_size2) { ff_log(FC_ERROR, 0, "mismatched secondary storage exact size: %" FT_ULL " bytes requested from command line, %" FT_ULL " bytes found in persistence file", (ft_ull) job_size2, persist_size2); err = -EINVAL; } if (err != 0) return err; // reuse persisted primary/secondary exact size. // ABSOLUTELY needed to reproduce the same operations while replaying size1 = (ft_size) persist_size1; size2 = (ft_size) persist_size2; return err; } /** set exact primary/secondary storage sizes. */ int fr_persist::set_storage_sizes_exact(ft_size size1, ft_size size2) { int err = 0; if (!this_replaying) err = do_write((ft_ull) size1, (ft_ull) size2); return err; } /** read a step from persistence fle */ int fr_persist::read(ft_ull & progress1, ft_ull & progress2) { if (!this_replaying) ff_log(FC_ERROR, 0, "tried to read after end of persistence file '%s'", this_persist_path.c_str()); progress1 = this_progress1; progress2 = this_progress2; return do_read(this_progress1, this_progress2); } /** read or write a step in persistence fle */ int fr_persist::next(ft_ull progress1, ft_ull progress2) { ff_log(FC_DEBUG, 0, "blocks left: device = %" FT_ULL ", storage = %" FT_ULL ", replaying = %s", progress1, progress2, this_replaying ? "true" : "false"); if (!this_replaying) return do_write(progress1, progress2); if (progress1 != this_progress1 || progress2 != this_progress2) { ff_log(FC_ERROR, 0, "unexpected values found while replaying persistence file '%s'", this_persist_path.c_str()); ff_log(FC_ERROR, 0, "\texpected %" FT_ULL " %" FT_ULL ", found %" FT_ULL " %" FT_ULL "\n", progress1, progress2, this_progress1, this_progress2); return -EINVAL; } return do_read(this_progress1, this_progress2); } /** try to read data from persistence fle */ int fr_persist::do_read(ft_ull & progress1, ft_ull & progress2) { int err = 0; if (this_replaying) { int items = fscanf(this_persist_file, "%" FT_ULL "\t%" FT_ULL "\n", & progress1, & progress2); if (items == 2) { /* ok */ } else if (feof(this_persist_file)) { this_replaying = false; } else { ff_log(FC_ERROR, 0, "corrupted persistence file '%s'! expecting two numeric values, found %d", this_persist_path.c_str(), (int) items); err = -EFAULT; } } return err; } /** try to write data into persistence fle */ int fr_persist::do_write(ft_ull progress1, ft_ull progress2) { if (fprintf(this_persist_file, "%" FT_ULL "\t%" FT_ULL "\n", progress1, progress2) <= 0) return ff_log(FC_ERROR, errno, "I/O error writing to persistence file '%s'", this_persist_path.c_str()); return do_flush(); } /** flush this_persist_file to disk: calls fflush() then fdatasync() or fsync() */ int fr_persist::do_flush() { if (fflush(this_persist_file) == 0) { int fd = fileno(this_persist_file); if (fd < 0) return ff_log(FC_ERROR, errno, "fileno('%s') failed: return value = %d", this_persist_path.c_str(), fd); #if defined(FT_HAVE_FDATASYNC) if (fdatasync(fd) == 0) #elif defined(FT_HAVE_FSYNC) if (fsync(fd) == 0) #else (void) sync(); #endif return 0; } return ff_log(FC_ERROR, errno, "I/O error flushing persistence file '%s'", this_persist_path.c_str()); } /** close persistence file */ int fr_persist::close() { if (this_persist_file != NULL) { if (fclose(this_persist_file) != 0) { return ff_log(FC_ERROR, errno, "failed to close persistence file '%s'", this_persist_path.c_str()); } this_persist_file = NULL; } return 0; } /** destructor */ fr_persist::~fr_persist() { (void) close(); } FT_IO_NAMESPACE_END fstransform-0.9.4/fsremap/src/io/persist.hh000066400000000000000000000063071345021500300207340ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/persist.hh * * Created on: Mar 6, 2011 * Author: max */ #ifndef FSREMAP_PERSIST_HH #define FSREMAP_PERSIST_HH #include "../job.hh" // for fr_job #if defined(FT_HAVE_STDIO_H) # include // for FILE. also for fopen(), fclose(), fprintf() and fscanf() used in persist.cc #elif defined(FT_HAVE_CSTDIO) # include // for FILE. also for fopen(), fclose(), fprintf() and fscanf() used in persist.cc #endif FT_IO_NAMESPACE_BEGIN class fr_persist { private: ft_ull this_progress1, this_progress2; ft_string this_persist_path; FILE * this_persist_file; fr_job & this_job; /** true while replaying persistence */ bool this_replaying; /** cannot call copy constructor */ fr_persist(const fr_persist &); /** cannot call assignment operator */ const fr_persist & operator=(const fr_persist &); /** try to read data from persistence fle */ int do_read(ft_ull & progress1, ft_ull & progress2); /** try to write data into persistence fle */ int do_write(ft_ull progress1, ft_ull progress2); /** flush this_persist_file to disk: calls fflush() then fdatasync() or fsync() */ int do_flush(); public: /** constructor */ fr_persist(fr_job & job); /** return job */ FT_INLINE fr_job & job() { return this_job; } /** create and open persistence file job.job_dir() + "/fsremap.persist" */ int open(); /** return true if replaying persistence file */ FT_INLINE bool is_replaying() const { return this_replaying; } /** * get exact primary/secondary storage sizes. * also verify that sizes in persistence file (if present) match ones from command line (if specified). * if no exact sizes are available, sets them to 0. */ int get_storage_sizes_exact(ft_size & primary_size_exact, ft_size & secondary_size_exact); /** set exact primary/secondary storage sizes. */ int set_storage_sizes_exact(ft_size primary_size_exact, ft_size secondary_size_exact); /** read a step from persistence fle */ int read(ft_ull & progress1, ft_ull & progress2); /** read or write a step in persistence file */ int next(ft_ull progress1, ft_ull progress2); /** close persistence file */ int close(); /** destructor */ ~fr_persist(); }; FT_IO_NAMESPACE_END #endif /* FSREMAP_PERSIST_HH */ fstransform-0.9.4/fsremap/src/io/request.hh000066400000000000000000000062631345021500300207340ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/request.hh * * Created on: Mar 15, 2011 * Author: max */ #ifndef FSREMAP_IO_REQUEST_HH #define FSREMAP_IO_REQUEST_HH #include "../types.hh" // for ft_uoff #include "../extent.hh" // for fr_dir FT_IO_NAMESPACE_BEGIN /** * simple class containing details of an I/O request. * * class invariant: ff_can_sum(ff_max2(this_from, this_to), this_length) */ class ft_request { private: ft_uoff this_from; ft_uoff this_to; ft_uoff this_length; fr_dir this_dir; public: /** construct a request with no pending copies */ ft_request(); /** construct a request with specified values */ ft_request(ft_uoff from, ft_uoff to, ft_uoff length, fr_dir dir); /** compiler-generated copy constructor is ok */ // ft_request(const ft_request &); /** compiler-generated assignment operator is ok */ // const ft_request & operator=(const ft_request &); /** compiler-generated destructor is ok */ // ~ft_request(); /** forget and discard any requested copy */ void clear(); FT_INLINE ft_uoff from() const { return this_from; } FT_INLINE ft_uoff to() const { return this_to; } FT_INLINE ft_uoff length() const { return this_length; } FT_INLINE fr_dir dir() const { return this_dir; } FT_INLINE bool empty() const { return this_length == 0; } FT_INLINE bool is_from_dev() const { return ff_is_from_dev(this_dir); } FT_INLINE bool is_to_dev() const { return ff_is_to_dev(this_dir); } const char * label_from() const; const char * label_to() const; /** * forget any requested copy and set this request to specified values. * returns EOVERFLOW if max(from,to)+length overflows ft_uoff */ int assign(ft_uoff from, ft_uoff to, ft_uoff length, fr_dir dir); /** * coalesce this request with specified values, or return error if they cannot be coalesced. * possible errors: * ENOTDIR the two requests are not in the same direction * EINVAL the two requests are not consecutive, or coalescing them would overflow */ int coalesce(ft_uoff from, ft_uoff to, ft_uoff length, fr_dir dir); /** * remove 'length' bytes from the beginning of this request */ int remove_front(ft_uoff length); }; FT_IO_NAMESPACE_END #endif /* FSREMAP_IO_REQUEST_HH */ fstransform-0.9.4/fsremap/src/io/util_dir.cc000066400000000000000000000055541345021500300210470ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/util.cc * * Created on: Mar 6, 2011 * Author: max */ #include "../first.hh" #include "../types.hh" // for ft_mode #include "../log.hh" // for ff_log #if defined(FT_HAVE_STRING_H) # include // for memchr() #elif defined(FT_HAVE_CSTRING) # include // for memchr() #endif #if defined(FT_HAVE_ERRNO_H) # include // for errno #elif defined(FT_HAVE_CERRNO) # include // for errno #endif #ifdef FT_HAVE_SYS_STAT_H # include // for mkdir() #endif #ifdef FT_HAVE_SYS_TYPES_H # include // for mkdir() #endif FT_IO_NAMESPACE_BEGIN /** * create a directory, return 0 (success) or error. * note: path MUST NOT end with '/' */ int ff_mkdir(const char * path, ft_mode mode) { #ifdef __USE_POSIX int err = mkdir(path, mode); return err != 0 ? errno : 0; #else return ENOSYS; #endif } int ff_mkdir_or_warn(const char * path, ft_mode mode) { int err = ff_mkdir(path, mode); if (err != 0 && err != EEXIST) err = ff_log(FC_WARN, err, "failed to create directory `%s'", path); return err; } int ff_mkdir_recursive(const ft_string & path) { ft_string partial; size_t len = path.length(); const char * start = path.c_str(), * slash, * prev = start, * end = start + len; int err = 0; partial.reserve(len); while ((slash = (const char *)memchr(prev, '/', end - prev)) != NULL) { // if path starts with "/", try to create "/", NOT the unnamed directory "" partial.assign(start, slash == start ? 1 : slash - start); err = ff_mkdir_or_warn(partial.c_str(), 0700); if (err != 0 && err != EEXIST) return err; prev = slash + 1; } // if path does not end with "/", create the last segment if (len != 0 && prev != end) err = ff_mkdir_or_warn(path.c_str(), 0700); return err; } int ff_remove_recursive(const ft_string & FT_ARG_UNUSED(path)) { return ENOSYS; } FT_IO_NAMESPACE_END fstransform-0.9.4/fsremap/src/io/util_dir.hh000066400000000000000000000035271345021500300210570ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/util.hh * * Created on: Mar 6, 2011 * Author: max */ #ifndef FSREMAP_UTIL_DIR_HH #define FSREMAP_UTIL_DIR_HH #include "../types.hh" FT_IO_NAMESPACE_BEGIN /** * create a directory, return 0 (success) or error. * note: path MUST NOT end with '/' * * depending on the caller expectations whether the directory * can already exist or not, error==EEXIST may also indicate success */ int ff_mkdir(const char * path, ft_mode mode = 0755); /** * same as ff_mkdir(), plus calls ff_log(WARN) on errors. * if error==EEXIST, it is returned but not logged. */ int ff_mkdir_or_warn(const char * path, ft_mode mode = 0755); /** * create a directory, return 0 (success) or error. * * depending on the caller expectations whether the directory * can already exist or not, error==EEXIST may also indicate success */ int ff_mkdir_recursive(const ft_string & path); int ff_remove_recursive(const ft_string & path); FT_IO_NAMESPACE_END #endif /* FSREMAP_UTIL_DIR_HH */ fstransform-0.9.4/fsremap/src/io/util_posix.cc000066400000000000000000000250201345021500300214210ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/util_posix.cc * * Created on: Feb 24, 2011 * Author: max */ #include "../first.hh" #if defined(FT_HAVE_ERRNO_H) # include // for errno, EOVERFLOW, ENOTBLK, EINTR #elif defined(FT_HAVE_CERRNO) # include // for errno, EOVERFLOW, ENOTBLK, EINTR #endif #if defined(FT_HAVE_STDLIB_H) # include // for exit(), posix_fallocate() #elif defined(FT_HAVE_CSTDLIB) # include // for exit(), posix_fallocate() #endif #ifdef FT_HAVE_FCNTL_H # include // for fallocate() #endif #ifdef FT_HAVE_UNISTD_H # include // for fork(), execvp() #endif #ifdef FT_HAVE_SYS_IOCTL_H # include // for ioctl() #endif #ifdef FT_HAVE_SYS_STAT_H # include // for stat() #endif #ifdef FT_HAVE_SYS_TYPES_H # include // for waitpid() #endif #ifdef FT_HAVE_SYS_WAIT_H # include // for " #endif #ifdef FT_HAVE_SYS_DISKLABEL_H # include // for struct disklabel on *BSD #endif #ifdef FT_HAVE_LINUX_FS_H # include // for BLKGETSIZE64 on Linux #endif #include "../types.hh" // for ft_u64, ft_stat #include "../log.hh" // for ff_log() #include "../misc.hh" // for ff_min2() #include "util_posix.hh" // for ff_posix_ioctl(), ff_posix_stat(), ff_posix_size(), ff_filedev() FT_IO_NAMESPACE_BEGIN /** invoke ioctl() */ int ff_posix_ioctl(int fd, int request, void * arg) { return ioctl(fd, request, arg) == 0 ? 0 : errno; } /** return file stats in (*ret_stat) */ int ff_posix_stat(int fd, ft_stat * ret_stat) { int err = fstat(fd, ret_stat); if (err != 0) err = errno; return err; } /** return file stats in (*ret_stat) */ int ff_posix_stat(const char * path, ft_stat * ret_stat) { int err = lstat(path, ret_stat); if (err != 0) err = ff_log(FC_ERROR, errno, "error in lstat(%s)", path); return err; } /** return block size of file-system containing file */ int ff_posix_blocksize(int fd, ft_uoff * ret_block_size) { ft_stat st_buf; int err = ff_posix_stat(fd, & st_buf); if (err == 0) { ft_uoff block_size; if ((err = ff_narrow(st_buf.st_blksize, & block_size)) == 0) * ret_block_size = block_size; } return err; } /** return file size in (*ret_size) */ int ff_posix_size(int fd, ft_uoff * ret_size) { ft_stat st_buf; int err = ff_posix_stat(fd, & st_buf); if (err == 0) { ft_uoff file_size; if ((err = ff_narrow(st_buf.st_size, & file_size)) == 0) * ret_size = file_size; } return err; } /** return ID of device containing file in (*ret_dev) */ int ff_posix_dev(int fd, dev_t * ret_dev) { ft_stat st_buf; int err = ff_posix_stat(fd, & st_buf); if (err == 0) * ret_dev = st_buf.st_dev; return err; } /** if file is special block device, return its device ID in (*ret_dev) */ int ff_posix_blkdev_dev(int fd, ft_dev * ret_dev) { ft_stat st_buf; int err = ff_posix_stat(fd, & st_buf); if (err == 0) { if ((st_buf.st_mode & S_IFBLK)) * ret_dev = st_buf.st_rdev; else err = ENOTBLK; } return err; } /** if file is special block device, return its length in (*ret_size) */ int ff_posix_blkdev_size(int fd, ft_uoff * ret_size) { #if defined(DIOCGDINFO) && defined(FT_HAVE_STRUCT_DISKLABEL_D_SECSIZE) && defined(FT_HAVE_STRUCT_DISKLABEL_D_SECPERUNIT) // *BSD struct disklabel dl; int err = ff_posix_ioctl(fd, DIOCGDINFO, & dl); if (err == 0) { if (dl.d_secsize <= 0 || dl.d_secperunit <= 0) err = EINVAL; // invalid size else { ft_uoff dev_sector_size = (ft_uoff) dl.d_secsize; ft_uoff dev_sector_count = (ft_uoff) dl.d_secperunit; if (dev_sector_size != dl.d_secsize || dev_sector_count != dl.d_secperunit) err = EOVERFLOW; // sector size or sector count cannot be represented by ft_uoff! else { ft_uoff dev_size = dev_sector_size * dev_sector_count; // check for multiplication overflow if (dev_size / dev_sector_size != dev_sector_count) err = EOVERFLOW; // device size cannot be represented by ft_uoff! else * ret_size = dev_size; } } } #elif defined(BLKGETSIZE64) // Linux ft_u64 size_u64 = 0; int err = ff_posix_ioctl(fd, BLKGETSIZE64, & size_u64); if (err == 0) { if (size_u64 <= 0) err = EINVAL; // invalid size else if (size_u64 > (ft_uoff)-1) err = EOVERFLOW; // device size cannot be represented by ft_uoff! else * ret_size = (ft_uoff) size_u64; } #else // Linux, obsolete: BLKGETSIZE returns device size DIVIDED 512 unsigned long size_div_512 = 0; int err = ff_posix_ioctl(fd, BLKGETSIZE, & size_div_512); if (err == 0) { if (size_div_512 <= 0) err = EINVAL; // invalid size else if (size_div_512 > ((ft_uoff)-1 >> 9)) err = EOVERFLOW; // device size cannot be represented by ft_uoff! else * ret_size = (ft_uoff) size_div_512 << 9; } #endif return err; } /** * seek file descriptor to specified position from file beginning. * note: if an error is returned, file descriptor position will be undefined! */ int ff_posix_lseek(int fd, ft_uoff pos) { off_t pos_s = (off_t)pos; if (pos_s < 0 || pos != (ft_uoff) pos_s) return EOVERFLOW; if ((pos_s = lseek(fd, pos_s, SEEK_SET)) < 0) return errno; if (pos != (ft_uoff) pos_s) return ESPIPE; return 0; } /** * read from a file descriptor. * keep retrying in case of EINTR or short reads. */ int ff_posix_read(int fd, void * mem, ft_uoff length) { ft_uoff chunk, max = (ft_uoff)((size_t)(ssize_t)-1 >> 1); /**< max = std::numeric_limits::max() */ ssize_t got; while (length != 0) { chunk = ff_min2(length, max); while ((got = ::read(fd, mem, (size_t)chunk)) < 0 && errno == EINTR) ; if (got < 0) return errno; if (got == 0) /* end-of-file */ break; if ((ft_uoff) got >= length) break; mem = (void *)((char *)mem + got); length -= (ft_uoff) got; } return 0; } /** * write to a file descriptor. * keep retrying in case of EINTR or short writes. */ int ff_posix_write(int fd, const void * mem, ft_uoff length) { ft_uoff chunk, max = (ft_uoff)((size_t)(ssize_t)-1 >> 1); /**< max = std::numeric_limits::max() */ ssize_t sent; while (length != 0) { chunk = ff_min2(length, max); while ((sent = ::write(fd, mem, (size_t)chunk)) < 0 && errno == EINTR) ; if (sent < 0) return errno; if (sent == 0) /* end-of-file */ break; if ((ft_uoff) sent >= length) break; mem = (const void *)((const char *)mem + sent); length -= (ft_uoff) sent; } return 0; } /** * preallocate and fill with zeroes 'length' bytes on disk for a file descriptor. * uses fallocate() if available, else posix_fallocate(), else plain write() loop. */ int ff_posix_fallocate(int fd, ft_off length, const ft_string & err_msg) { int err = 0; #if defined(FT_HAVE_FALLOCATE) if ((err = fallocate(fd, 0, 0, length)) != 0) #elif defined(FT_HAVE_POSIX_FALLOCATE) if ((err = posix_fallocate(fd, 0, length)) != 0) #endif /* FT_HAVE_FALLOCATE */ { /* fall back on write() */ enum { zero_len = 64*1024 }; char zero[zero_len]; ft_off pos = 0; ft_size chunk; while (pos < length) { // safe cast ft_uoff -> ft_size, the value is <= zero_len chunk = (ft_size) ff_min2(zero_len, length - pos); if ((err = ff_posix_write(fd, zero, chunk)) != 0) { err = ff_log(FC_ERROR, errno, "%s", err_msg.c_str()); break; } pos += chunk; } } return err; } /** * spawn a system command, typically with fork()+execv(), wait for it to complete and return its exit status. * argv[0] is conventionally the program name. * argv[1...] are program arguments and must be terminated with a NULL pointer. */ int ff_posix_exec(const char * path, const char * const argv[]) { int err; pid_t pid = ::fork(); if (pid == 0) { /* child */ ::execvp(path, (char * const *)argv); /* if we reach here, execvp() failed! */ ff_log(FC_ERROR, err = errno, "execvp(%s) failed"); /* exit() can only return one-byte exit status */ err &= 0xff; if (err == 0) { err = (ECHILD > 0 ? ECHILD : -ECHILD) & 0xff; if (err == 0) err = 1; } ::exit(err); } else if (pid == (pid_t)-1) { err = ff_log(FC_ERROR, errno, "fork() failed"); } else { /* parent */ err = -ECHILD; // assume failure unless proved successful... int status = 0; if (waitpid(pid, & status, 0/*options*/) != pid) { err = ff_log(FC_ERROR, errno, "error in waitpid(), assuming command '%s' failed", path); if (err == 0) err = -ECHILD; } else if (WIFEXITED(status)) { status = WEXITSTATUS(status); if (status == 0) err = 0; // proved successful! else ff_log(FC_ERROR, 0, "command '%s' exited with non-zero exit status %d", path, status); } else if (WIFSIGNALED(status)) ff_log(FC_ERROR, 0, "command '%s' died with signal %d", path, (int)WTERMSIG(status)); else ff_log(FC_ERROR, 0, "waitpid() returned unknown status %d, assuming command '%s' failed", status, path); } return err; } FT_IO_NAMESPACE_END fstransform-0.9.4/fsremap/src/io/util_posix.hh000066400000000000000000000061711345021500300214410ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * io/util_posix.hh * * Created on: Feb 24, 2011 * Author: max */ #ifndef FSREMAP_IO_POSIX_UTIL_HH #define FSREMAP_IO_POSIX_UTIL_HH #include "../types.hh" // for ft_uoff, ft_stat, ft_dev, ft_mode */ FT_IO_NAMESPACE_BEGIN /** invoke ioctl() */ int ff_posix_ioctl(int fd, int request, void * arg); /** return file stats in (*ret_stat) */ int ff_posix_stat(int fd, ft_stat * ret_stat); /** return file stats in (*ret_stat) */ int ff_posix_stat(const char * path, ft_stat * ret_stat); /** return file size in (*ret_size) */ int ff_posix_size(int fd, ft_uoff * ret_size); /** return block size of file-system containing file */ int ff_posix_blocksize(int fd, ft_uoff * ret_block_size); /** return ID of device containing file in (*ret_dev) */ int ff_posix_dev(int fd, ft_dev * ret_dev); /** if file is special block device, return its device ID in (*ret_dev) */ int ff_posix_blkdev_dev(int fd, ft_dev * ret_dev); /** if file is special block device, return its length in (*ret_dev) */ int ff_posix_blkdev_size(int fd, ft_uoff * ret_size); /** * seek file descriptor to specified position from file beginning. * note: if an error is returned, file descriptor position will be undefined! */ int ff_posix_lseek(int fd, ft_uoff pos); /** * read from a file descriptor. * keep retrying in case of EINTR or short reads. * on return, ret_length will be increased by the number of bytes actually read */ int ff_posix_read(int fd, void * mem, ft_uoff length); /** * write to a file descriptor. * keep retrying in case of EINTR or short writes. * on return, ret_length will be increased by the number of bytes actually written */ int ff_posix_write(int fd, const void * mem, ft_uoff length); /** * preallocate and fill with zeroes 'length' bytes on disk for a file descriptor. * uses fallocate() if available, else posix_fallocate(), else plain write() loop. */ int ff_posix_fallocate(int fd, ft_off length, const ft_string & err_msg); /** * spawn a system command, wait for it to complete and return its exit status. * argv[0] is conventionally the program name. * argv[1...] are program arguments and must be terminated with a NULL pointer. */ int ff_posix_exec(const char * path, const char * const argv[]); FT_IO_NAMESPACE_END #endif /* FSREMAP_IO_POSIX_UTIL_HH */ fstransform-0.9.4/fsremap/src/job.cc000066400000000000000000000130451345021500300173710ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * job.cc * * Created on: Mar 9, 2011 * Author: max */ #include "first.hh" #if defined(FT_HAVE_ERRNO_H) # include // for errno #elif defined(FT_HAVE_CERRNO) # include // for errno #endif #if defined(FT_HAVE_STDLIB_H) # include // for malloc(), free(), getenv() #elif defined(FT_HAVE_CSTDLIB) # include // for malloc(), free(), getenv() #endif #if defined(FT_HAVE_STRING_H) # include // for memcpy() #elif defined(FT_HAVE_CSTRING) # include // for memcpy() #endif #include "args.hh" // for FC_JOB_ID_AUTODETECT #include "job.hh" // for fr_job #include "io/util_dir.hh" // for ff_mkdir() FT_NAMESPACE_BEGIN /** default constructor */ fr_job::fr_job() : this_dir(), this_log_file(NULL), this_log_appender(NULL), this_id(FC_JOB_ID_AUTODETECT), this_clear(FC_CLEAR_AUTODETECT), this_force_run(false), this_simulate_run(false), this_resume_job(false), this_ask_questions(false) { for (ft_size i = 0; i < FC_STORAGE_SIZE_N; i++) this_storage_size[i] = 0; } /** destructor. calls quit() */ fr_job::~fr_job() { quit(); } /** initialize this job, or return error */ int fr_job::init(const fr_args & args) { if (args.root_dir != NULL) this_dir = args.root_dir; else this_dir = "/var/tmp"; const char * path = this_dir.c_str(); (void) FT_IO_NS ff_mkdir(path); this_dir += "/fstransform"; path = this_dir.c_str(); (void) FT_IO_NS ff_mkdir(path); this_dir += "/fsremap.job."; ft_size len = this_dir.size(); ft_uint i, job_min = 1, job_max = 1000000; int err = 0; /* copy flags */ this_resume_job = args.job_id != FC_JOB_ID_AUTODETECT; this_force_run = args.force_run; this_simulate_run = args.simulate_run; this_ask_questions = args.ask_questions; if (this_resume_job) /* force job_id */ job_min = args.job_id, job_max = args.job_id + 1; path = this_dir.c_str(); for (i = job_min; i != job_max; i++) { // 1 + 3*sizeof(ft_uint) chars are enough to safely print (ft_uint) this_dir.resize(len + 2 + 3*sizeof(ft_uint)); sprintf(& this_dir[len], "%" FT_ULL , (ft_ull) i); this_dir.resize(len + strlen(& this_dir[len])); path = this_dir.c_str(); if (!this_resume_job) err = FT_IO_NS ff_mkdir(path); if (err == 0 && (err = init_log()) == 0) { ff_log(FC_NOTICE, 0, "fsremap: %s job %" FT_ULL ", persistence data and logs are in '%s'", this_resume_job ? "resuming" : "starting", (ft_ull)i, path); if (!this_resume_job && !this_simulate_run && args.io_kind != FC_IO_SELF_TEST) { ff_log(FC_NOTICE, 0, "if this job is interrupted, for example by a power failure,"); ff_log(FC_NOTICE, 0, "you CAN RESUME it with: %s%s -q --resume-job=%" FT_ULL " -- %s", args.program_name, this_simulate_run ? " -n" : "", (ft_ull)i, args.io_args[0]); } break; } } if (i == job_max) { if (this_resume_job) err = ff_log(FC_ERROR, err, "failed to resume job id %" FT_ULL " from directory '%s'", (ft_ull) args.job_id, path); else err = ff_log(FC_ERROR, err, "failed to locate a free job id, tried range %" FT_ULL "...%" FT_ULL , (ft_ull) job_min, (ft_ull) (job_max-1)); } if (err != 0) { quit(); return err; } for (ft_size l = 0; l < FC_STORAGE_SIZE_N; l++) this_storage_size[l] = args.storage_size[l]; this_id = i; this_clear = args.job_clear; return err; } /** initialize logging subsystem, or return error */ int fr_job::init_log() { ft_string log_file_name = this_dir; log_file_name += "/fsremap.log"; const char * log_file = log_file_name.c_str(); if ((this_log_file = fopen(log_file, "a")) == NULL) return ff_log(FC_ERROR, errno, "failed to open log file '%s'", log_file); (void) setvbuf(this_log_file, NULL, _IOLBF, 0); /* note 1.4.3) fsremap.log always uses FC_FMT_DATETIME_LEVEL_CALLER_MSG */ this_log_appender = new ft_log_appender(this_log_file, FC_FMT_DATETIME_LEVEL_CALLER_MSG); ft_log::get_root_logger().add_appender(* this_log_appender); return 0; } void fr_job::quit() { if (this_log_appender != NULL) { ft_log::get_root_logger().remove_appender(* this_log_appender); this_log_appender = NULL; } if (this_log_file != NULL) { fclose(this_log_file); this_log_file = NULL; } this_dir.clear(); for (ft_size i = 0; i < FC_STORAGE_SIZE_N; i++) this_storage_size[i] = 0; this_id = FC_JOB_ID_AUTODETECT; } FT_NAMESPACE_END fstransform-0.9.4/fsremap/src/job.hh000066400000000000000000000107651345021500300174110ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * log.hh * * Created on: Mar 8, 2011 * Author: max */ #ifndef FSREMAP_JOB_HH #define FSREMAP_JOB_HH #include "types.hh" // for ft_size, ft_uint, ft_string #if defined(FT_HAVE_STDIO_H) # include // for FILE. also for sprintf() used in job.cc #elif defined(FT_HAVE_CSTDIO) # include // for FILE. also for sprintf() used in job.cc #endif #include "args.hh" // for fr_args, FC_STORAGE_SIZE_N #include "log.hh" // for ft_log_appender FT_NAMESPACE_BEGIN class fr_job { private: ft_string this_dir; ft_size this_storage_size[FC_STORAGE_SIZE_N]; FILE * this_log_file; ft_log_appender * this_log_appender; ft_uint this_id; fr_clear_free_space this_clear; bool this_force_run, this_simulate_run, this_resume_job, this_ask_questions; /** initialize logging subsystem */ int init_log(); public: /** default constructor */ fr_job(); /** destructor. calls quit() */ ~fr_job(); /** initialize this job, or return error */ int init(const fr_args & args); /** quit this job */ void quit(); /** return job_id, or 0 if not set */ FT_INLINE ft_uint job_id() const { return this_id; } /** return job_dir, or empty if not set */ FT_INLINE const ft_string & job_dir() const { return this_dir; } /** return secondary storage, buffer, or primary/secondary exact length to use (in bytes). 0 means autodetect */ FT_INLINE ft_size job_storage_size(fr_storage_size which) const { return this_storage_size[which]; } /** set secondary storage, buffer, or primary/secondary exact length to use (in bytes), or 0 to activate autodetection */ FT_INLINE void job_storage_size(fr_storage_size which, ft_size len) { this_storage_size[which] = len; } /** * return which free blocks to clear after remapping: * all, only blocks used as primary storage or renumbered device, or none */ FT_INLINE fr_clear_free_space job_clear() const { return this_clear; } /** * set which free blocks to clear after remapping: * all, only blocks used as primary storage or renumbered device, or none */ FT_INLINE void job_clear(fr_clear_free_space clear) { this_clear = clear; } /** * return true if I/O classes should be less strict on sanity checks * and generate WARNINGS (and keep going) for failed sanity checks * instead of generating ERRORS (and quitting) */ FT_INLINE bool force_run() const { return this_force_run; } /** * set to true if I/O classes should be less strict on sanity checks * and generate WARNINGS (and keep going) for failed sanity checks * instead of generating ERRORS (and quitting) */ FT_INLINE void force_run(bool force_flag) { this_force_run = force_flag; } /** return true if I/O classes should simulate run, i.e. run WITHOUT reading or writing device blocks */ FT_INLINE bool simulate_run() const { return this_simulate_run; } /** set to true if I/O classes should simulate run, i.e. run WITHOUT reading or writing device blocks */ FT_INLINE void simulate_run(bool simulate_flag) { this_simulate_run = simulate_flag; } /** return true if resuming an existing job */ FT_INLINE bool resuming_job() const { return this_resume_job; } /** return true if classes can ask questions to the user and read answers from stdin */ FT_INLINE bool ask_questions() const { return this_ask_questions; } /** set to true if classes can ask questions to the user and read answers from stdin */ FT_INLINE void ask_questions(bool ask_flag) { this_ask_questions = ask_flag; } }; FT_NAMESPACE_END #endif /* FSREMAP_JOB_HH */ fstransform-0.9.4/fsremap/src/log.cc000066400000000000000000000376151345021500300174110ustar00rootroot00000000000000/* * logging utilities for fsattr, fsmove, fsremap * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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, see . * * log.cc * * Created on: Mar 8, 2011 * Author: max */ #include "first.hh" #if defined(FT_HAVE_STRING_H) # include // for strerror(), strncmp() #elif defined(FT_HAVE_CSTRING) # include // for strerror(), strncmp() #endif #if defined(FT_HAVE_TIME_H) # include // for time(), localtime_r(), localtime(), strftime() #elif defined(FT_HAVE_CTIME) # include // for time(), localtime_r(), localtime(), strftime() #endif #if defined(FT_HAVE_UNISTD_H) # include /* for isatty() */ #endif #include // for std::make_pair() #include "types.hh" // for ft_size #include "log.hh" // for ff_log(), ff_vlog() ... #if defined(FT_HAVE_VA_COPY) || defined(va_copy) # define ff_va_copy va_copy #elif defined(FT_HAVE___VA_COPY) || defined(__va_copy) # define ff_va_copy __va_copy #else # error both va_copy() and __va_copy() are missing, cannot compile log.cc #endif FT_NAMESPACE_BEGIN static char const* const this_log_label[FC_FATAL+1] = { "", "DUMP ", "TRACE ", "DEBUG ", "INFO ", "NOTICE", "WARN ", "ERROR ", "FATAL ", }; static char const* const this_log_label_always[FC_FATAL+1] = { "", "", "", "", "", "", "WARN: ", "ERROR: ", "FATAL: ", }; static char const* const this_log_color_ansi[FC_FATAL+1] = { "", "\033[1;30m", "\033[1;30m", "\033[1;30m", "", "\033[1m", "\033[1;33m", "\033[1;31m", "\033[1;35m", }; static char const* const this_log_color_ansi_off_nl = "\033[0m\n"; const char * ff_log_level_to_string(ft_log_level level) { if (level >= FC_LEVEL_NOT_SET && level <= FC_FATAL) return this_log_label[level]; if (level == FC_LEVEL_NOT_SET) return "NOT_SET"; return "UNKNOWN"; } static ft_log_appenders * fc_log_all_appenders = NULL; static all_loggers_type * fc_log_all_loggers = NULL; static ft_log * fc_log_root_logger = NULL; static bool fc_log_initialized = false; /** list of all appenders */ ft_log_appenders & ft_log_appender::get_all_appenders() { if (!fc_log_initialized) ft_log::initialize(); return * fc_log_all_appenders; } /** constructor. */ ft_log_appender::ft_log_appender(FILE * my_stream, ft_log_fmt my_format, ft_log_level my_min_level, ft_log_level my_max_level, ft_log_color my_color) : stream(my_stream), format(my_format), min_level(my_min_level), max_level(my_max_level), color(my_color) { get_all_appenders().insert(this); } /** destructor. */ ft_log_appender::~ft_log_appender() { flush(); get_all_appenders().erase(this); } /** * write a log message to stream. * * print fmt and subsequent printf-style args to log stream. * if err != 0, append ": ", strerror(errno) and "\n" * else append "\n" */ void ft_log_appender::append(ft_log_event & event) { const ft_log_level level = event.level; if (level < min_level || level > max_level) return; const char * color_on = "", * color_off_nl = "\n"; #if defined(FT_HAVE_ISATTY) && defined(FT_HAVE_FILENO) if (color == FC_COL_AUTO) color = (isatty(fileno(stream)) == 1) ? FC_COL_ANSI : FC_COL_NONE; #endif if (color == FC_COL_ANSI) { color_on = this_log_color_ansi[level]; color_off_nl = this_log_color_ansi_off_nl; } switch (format) { case FC_FMT_DATETIME_LEVEL_CALLER_MSG: fprintf(stream, "%s%s %s [%.*s%s.%s(%d)]\t", color_on, event.str_now, this_log_label[level], event.file_len, event.file, event.file_suffix, event.function, event.line); break; case FC_FMT_DATETIME_LEVEL_MSG: fprintf(stream, "%s%s %s ", color_on, event.str_now, this_log_label[level]); break; case FC_FMT_LEVEL_MSG: fprintf(stream, "%s%s ", color_on, this_log_label[level]); break; case FC_FMT_MSG: default: /* always mark warnings, errors and fatal errors as such */ fprintf(stream, "%s%s", color_on, this_log_label_always[level]); break; } va_list vargs; ff_va_copy(vargs, event.vargs); vfprintf(stream, event.fmt, vargs); va_end(vargs); if (event.err != 0) { bool is_reported = ff_log_is_reported(event.err); fprintf(stream, is_reported ? " (caused by previous error: %s)%s" : ": %s%s", strerror(is_reported ? -event.err : event.err), color_off_nl); } else fputs(color_off_nl, stream); } /** flush this appender */ void ft_log_appender::flush() { fflush(stream); } /** flush all buffered streams used to log messages for specified level */ void ft_log_appender::flush_all(ft_log_level level) { ft_log_appenders & all_appenders = get_all_appenders(); ft_log_appenders_citerator iter = all_appenders.begin(), end = all_appenders.end(); /* iterate on streams configured for 'level' */ for (; iter != end; ++iter) { ft_log_appender * appender = *iter; if (appender->min_level <= level && appender->max_level >= level) appender->flush(); } } /** set format, min level and color of this appender */ void ft_log_appender::reconfigure(ft_log_fmt format_except_fatal, ft_log_level stdout_min_level, ft_log_color color) { if (this->max_level != FC_FATAL) this->format = format_except_fatal; if (stdout_min_level != FC_LEVEL_NOT_SET && this->stream == stdout) this->min_level = stdout_min_level; this->color = color; } /** set format, min level and color of all appenders */ void ft_log_appender::reconfigure_all(ft_log_fmt format_except_fatal, ft_log_level stdout_min_level, ft_log_color color) { ft_log_appenders & all_appenders = get_all_appenders(); ft_log_appenders_citerator iter = all_appenders.begin(), end = all_appenders.end(); for (; iter != end; ++iter) (*iter)->reconfigure(format_except_fatal, stdout_min_level, color); } /** return map of all existing loggers. */ all_loggers_type & ft_log::get_all_loggers() { if (!fc_log_initialized) ft_log::initialize(); return * fc_log_all_loggers; } /** return root logger. by default, all messages less serious than 'FC_INFO' are suppressed on all streams */ ft_log & ft_log::get_root_logger() { if (!fc_log_initialized) ft_log::initialize(); return * fc_log_root_logger; } /** * initialize log subsystem. automatic configuration is: * * print to stderr all INFO and NOTICE messages, with format FC_FMT_MSG * print to stdout all WARN, ERROR and FATAL messages, with format FC_FMT_MSG */ void ft_log::initialize() { if (fc_log_initialized) return; fc_log_initialized = true; #ifdef FT_HAVE_TZSET tzset(); #endif (void) setvbuf(stdout, NULL, _IOLBF, 0); (void) setvbuf(stderr, NULL, _IOLBF, 0); if (fc_log_all_appenders == NULL) fc_log_all_appenders = new ft_log_appenders(); if (fc_log_all_loggers == NULL) fc_log_all_loggers = new all_loggers_type(); if (fc_log_root_logger == NULL) fc_log_root_logger = new ft_log("", NULL, FC_INFO); ft_log & root_logger = get_root_logger(); root_logger.add_appender(* new ft_log_appender(stdout, FC_FMT_MSG, FC_DUMP, FC_NOTICE)); root_logger.add_appender(* new ft_log_appender(stderr, FC_FMT_MSG, FC_WARN, FC_ERROR)); root_logger.add_appender(* new ft_log_appender(stderr, FC_FMT_DATETIME_LEVEL_CALLER_MSG, FC_FATAL)); } /** constructor. */ ft_log::ft_log(const ft_mstring & my_name, ft_log * my_parent, ft_log_level my_level) : parent(my_parent), appenders(), level(my_level), effective_level(FC_LEVEL_NOT_SET), threshold_level(FC_LEVEL_NOT_SET) { std::pair iter_pair = get_all_loggers().insert(std::make_pair(my_name, this)); name = & iter_pair.first->first; } /** destructor. */ ft_log::~ft_log() { get_all_loggers().erase(* name); if (parent == NULL) ft_log_appender::flush_all(FC_DUMP); } /** find or create parent logger given child name. */ ft_log & ft_log::get_parent(const ft_mstring & child_logger_name) { ft_size slash = child_logger_name.rfind('/'); if (slash == ft_mstring::npos) return get_root_logger(); ft_mstring parent_name(child_logger_name, 0, slash); return get_logger(parent_name); } /** find or create a logger by name */ ft_log & ft_log::get_logger(const ft_mstring & logger_name) { all_loggers_type & all_loggers = get_all_loggers(); all_loggers_iterator iter = all_loggers.find(logger_name); if (iter != all_loggers.end()) return * iter->second; ft_log & parent = get_parent(logger_name); return * new ft_log(logger_name, & parent); } /** log a message (skip threshold_level check) */ void ft_log::append(ft_log_event & event) { ft_log * logger = this; do { if (event.level >= logger->get_effective_level()) { ft_log_appenders_citerator iter = logger->appenders.begin(), end = logger->appenders.end(); for (; iter != end; ++iter) (* iter)->append(event); } logger = logger->parent; } while (logger != NULL); } /** log a message (unless it's suppressed) */ void ft_log::log(ft_log_event & event) { if (event.level >= get_threshold_level()) append(event); } /** return the effective level: if level is set return it, otherwise return parent effective level. */ ft_log_level ft_log::get_effective_level() const { if (effective_level == FC_LEVEL_NOT_SET) { if (level == FC_LEVEL_NOT_SET) effective_level = (parent != NULL) ? parent->get_effective_level() : FC_INFO; else effective_level = level; } return effective_level; } /** return the threshold level: the minimum of this and all ancestor's levels. */ ft_log_level ft_log::get_threshold_level() const { if (threshold_level == FC_LEVEL_NOT_SET) { ft_log_level effective_level = get_effective_level(); ft_log_level parent_threshold_level = (parent != NULL) ? parent->get_threshold_level() : effective_level; threshold_level = effective_level < parent_threshold_level ? effective_level : parent_threshold_level; } return threshold_level; } void ft_log::invalidate_all_cached_levels() { all_loggers_type & all_loggers = get_all_loggers(); all_loggers_iterator iter = all_loggers.begin(), end = all_loggers.end(); for (; iter != end; ++iter) { ft_log * logger = iter->second; logger->effective_level = logger->threshold_level = FC_LEVEL_NOT_SET; } } /** add an appender */ void ft_log::add_appender(ft_log_appender & appender) { appenders.insert(& appender); } /** remove an appender */ void ft_log::remove_appender(ft_log_appender & appender) { appender.flush(); appenders.erase(& appender); } static const char * ff_strftime(); static void ff_pretty_file(ft_log_event & event); bool ff_logl_is_enabled(const char * file, int file_len, ft_log_level level) { ft_log_event event = { "", file, "", "", "", file_len, 0, 0, level, /* va_list vargs field follows - but no portable way to value-initialize it */ }; ff_pretty_file(event); ft_mstring logger_name(event.file, event.file_len); ft_log & logger = ft_log::get_logger(logger_name); return logger.is_enabled(level); } /** * print fmt and subsequent printf-style args to log stream(s). * if err != 0, append ": ", strerror(errno) and "\n" * else append "\n" * finally return err */ int ff_logl(const char * file, int file_len, const char * func, int line, ft_log_level level, int err, const char * fmt, ...) { /* * note 1.1) * log subsystem is automatically initialized upon first call to * ff_log(), ff_vlog(), ff_log_register() or ff_log_set_threshold(). */ ft_log_event event = { ff_strftime(), file, "", func, fmt, file_len, line, err, level, /* va_list vargs field follows - but no portable way to value-initialize it */ }; ff_pretty_file(event); ft_mstring logger_name(event.file, event.file_len); ft_log & logger = ft_log::get_logger(logger_name); va_start(event.vargs, fmt); logger.log(event); va_end(event.vargs); /* note 1.2.1) ff_log() and ff_vlog() always return errors as reported (-EINVAL, -ENOMEM...) */ return ff_log_is_reported(err) ? err : -err; } /** * print to log fmt and subsequent printf-style args log stream(s). * if err != 0, append ": ", strerror(errno) and "\n" * else append "\n" * finally return err as reported (flip sign if it was unreported) */ int ff_logv(const char * file, int file_len, const char * func, int line, ft_log_level level, int err, const char * fmt, va_list vargs) { /* * note 1.1) * log subsystem is automatically initialized upon first call to * ff_log(), ff_vlog(), ff_log_register() or ff_log_set_threshold(). */ ft_log_event event = { ff_strftime(), file, "", func, fmt, file_len, line, err, level, /* va_list vargs field follows - but no portable way to value-initialize it */ }; ff_pretty_file(event); ft_mstring logger_name(event.file, event.file_len); ft_log & logger = ft_log::get_logger(logger_name); ff_va_copy(event.vargs, vargs); logger.log(event); va_end(event.vargs); /* note 1.2.1) ff_log() and ff_vlog() always return errors as reported (-EINVAL, -ENOMEM...) */ return ff_log_is_reported(err) ? err : -err; } enum { FC_SIZEOF_STR_NOW = 21 + 3*(sizeof(time_t)-4) }; static char this_str_now[FC_SIZEOF_STR_NOW]; static time_t this_time_now; /** * compute formatted timestamp for current time and return it in a static buffer. * used format is "%Y-%m-%d %H:%M:%S" */ static const char * ff_strftime() { time_t now = time(NULL); if (now != this_time_now) { #ifdef FT_HAVE_LOCALTIME_R struct tm tm_buf, * tm_now = & tm_buf; localtime_r(& now, tm_now); #else struct tm * tm_now = localtime(& now); #endif strftime(this_str_now, FC_SIZEOF_STR_NOW, "%Y-%m-%d %H:%M:%S", tm_now); this_str_now[FC_SIZEOF_STR_NOW - 1] = '\0'; this_time_now = now; } else { // cached this_str_now is still good } return this_str_now; } /** * compute pretty-print version of args.file (i.e. __FILE__): * skip any '../' or 'src/' prefix, * skip filename extension (for example .cc or .hh) * and replace final '.t' with '' */ static void ff_pretty_file(ft_log_event & event) { const char * file = event.file; int file_len = event.file_len; while (file_len >= 3 && !memcmp(file, "../", 3)) file += 3, file_len -= 3; if (file_len >= 8 && !memcmp(file, "fsremap/", 8)) file += 8, file_len -= 8; else if (file_len >= 7 && !memcmp(file, "fsmove/", 7)) file += 7, file_len -= 7; if (file_len >= 4 && !memcmp(file, "src/", 4)) file += 4, file_len -= 4; /** skip file extension, usually .cc or .hh */ const char * dot = (const char *) memrchr(file, '.', file_len); if (dot != NULL) file_len = dot - file; /** if file name ends with .t then replace with */ if (file_len >= 2 && file[file_len - 2] == '.' && file[file_len - 1] == 't') { file_len -= 2; event.file_suffix = ""; } event.file = file; event.file_len = file_len; } FT_NAMESPACE_END fstransform-0.9.4/fsremap/src/log.hh000066400000000000000000000204551345021500300174150ustar00rootroot00000000000000/* * logging utilities for fsattr, fsmove, fsremap * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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, see . * * log.hh * * Created on: Mar 8, 2011 * Author: max */ #ifndef FSTRANSFORM_LOG_HH #define FSTRANSFORM_LOG_HH #include "first.hh" #if defined(FT_HAVE_ERRNO_H) # include /* for EINVAL */ #elif defined(FT_HAVE_CERRNO) && defined(__cplusplus) # include /* for EINVAL */ #endif #if defined(FT_HAVE_STDARG_H) # include /* for va_list. also for va_start(), va_end(), va_copy() used by log.cc */ #elif defined(FT_HAVE_CSTDARG) && defined(__cplusplus) # include /* for va_list. also for va_start(), va_end(), va_copy() used by log.cc */ #endif #if defined(FT_HAVE_STDIO_H) # include /* for FILE. also for stdout, stderr, fprintf(), fileno() used by log.cc */ #elif defined(FT_HAVE_CSTDIO) && defined(__cplusplus) # include /* for FILE. also for stdout, stderr, fprintf(), fileno() used by log.cc */ #endif #include /* for std::set */ #include /* for std::map */ #include "mstring.hh" /* ft_mstring */ FT_NAMESPACE_BEGIN /** * note 1.1) * log subsystem is automatically initialized and configured upon first call to * ff_log(), ff_vlog(), ff_log_register_range(), ff_log_unregister_range() or ff_log_set_threshold(). * * automatic configuration is: * print to stdout all INFO and NOTICE messages, with format FC_FMT_MSG * print to stderr all WARN, ERROR and FATAL messages, with format FC_FMT_MSG */ /* FC_FATAL is reserved for things that should not happen, i.e. bugs in the program or in the operating system. */ enum ft_log_level { FC_LEVEL_NOT_SET = 0, FC_DUMP, FC_TRACE, FC_DEBUG, FC_INFO, FC_NOTICE, FC_WARN, FC_ERROR, FC_FATAL, FC_SHOW_DEFAULT_LEVEL = FC_TRACE }; enum ft_log_fmt { FC_FMT_MSG, /* message only */ FC_FMT_LEVEL_MSG, /* level + message */ FC_FMT_DATETIME_LEVEL_MSG, /* datetime + level + message */ FC_FMT_DATETIME_LEVEL_CALLER_MSG, /* datetime + level + [file.func(line)] + message */ }; enum ft_log_color { FC_COL_AUTO = 0, FC_COL_NONE, FC_COL_ANSI, }; /** * print to log fmt and subsequent printf-style args log stream(s). * if err != 0, append ": ", strerror(errno) and "\n" * else append "\n" * finally return err */ #define ff_log_is_enabled(level) ff_logl_is_enabled(FT_THIS_FILE, sizeof(FT_THIS_FILE)-1, level) #define ff_log(level, err, ...) ff_logl(FT_THIS_FILE, sizeof(FT_THIS_FILE)-1, FT_THIS_FUNCTION, FT_THIS_LINE, level, err, __VA_ARGS__) #define ff_vlog(level, err, fmt, vargs) ff_logv(FT_THIS_FILE, sizeof(FT_THIS_FILE)-1, FT_THIS_FUNCTION, FT_THIS_LINE, level, err, fmt, vargs) bool ff_logl_is_enabled(const char * caller_file, int caller_file_len, ft_log_level level); int ff_logl(const char * caller_file, int caller_file_len, const char * caller_func, int caller_line, ft_log_level level, int err, const char * fmt, ...); int ff_logv(const char * caller_file, int caller_file_len, const char * caller_func, int caller_line, ft_log_level level, int err, const char * fmt, va_list args); const char * ff_log_level_to_string(ft_log_level level); #if defined(EINVAL) && EINVAL < 0 # define ff_log_is_reported(err) ((err) >= 0) #else # define ff_log_is_reported(err) ((err) <= 0) #endif struct ft_log_event { const char * str_now, * file, * file_suffix, * function, * fmt; int file_len, line, err; ft_log_level level; va_list vargs; }; class ft_log_appender; typedef std::set ft_log_appenders; typedef ft_log_appenders::iterator ft_log_appenders_iterator; typedef ft_log_appenders::const_iterator ft_log_appenders_citerator; class ft_log_appender { private: FILE * stream; ft_log_fmt format; ft_log_level min_level, max_level; ft_log_color color; /** destructor. */ ~ft_log_appender(); /** list of all appenders */ static ft_log_appenders & get_all_appenders(); public: /** constructor. */ ft_log_appender(FILE * stream, ft_log_fmt format = FC_FMT_MSG, ft_log_level min_level = FC_DUMP, ft_log_level max_level = FC_FATAL, ft_log_color color = FC_COL_AUTO); FT_INLINE void set_format(ft_log_fmt format) { this->format = format; } FT_INLINE void set_min_level(ft_log_level min_level) { this->min_level = min_level; } FT_INLINE void set_max_level(ft_log_level max_level) { this->max_level = max_level; } /** write a log message to stream */ void append(ft_log_event & event); /** flush this appender */ void flush(); /** flush all buffered streams used to log messages for specified level */ static void flush_all(ft_log_level level); /** set format, min level and color of this appender */ void reconfigure(ft_log_fmt format_except_fatal = FC_FMT_MSG, ft_log_level stdout_min_level = FC_LEVEL_NOT_SET, ft_log_color color = FC_COL_AUTO); /** set format, min level and color of all appenders */ static void reconfigure_all(ft_log_fmt format_except_fatal = FC_FMT_MSG, ft_log_level stdout_min_level = FC_LEVEL_NOT_SET, ft_log_color color = FC_COL_AUTO); }; class ft_log; typedef std::map all_loggers_type; typedef all_loggers_type::iterator all_loggers_iterator; typedef all_loggers_type::const_iterator all_loggers_citerator; class ft_log { private: friend class ft_log_appender; const ft_mstring * name; ft_log * parent; ft_log_appenders appenders; ft_log_level level; /* events less severe than level will be suppressed */ mutable ft_log_level effective_level, threshold_level; /** initialize loggers and appenders. */ static void initialize(); /** return map of all existing loggers. */ static all_loggers_type & get_all_loggers(); /** constructor. */ ft_log(const ft_mstring & name, ft_log * parent, ft_log_level level = FC_LEVEL_NOT_SET); /** destructor. */ ~ft_log(); /** find or create a parent logger given child name. */ static ft_log & get_parent(const ft_mstring & child_logger_name); /** * invalidate all cached effective_level and threshold_level. * needed after some logger->level is changed. */ static void invalidate_all_cached_levels(); /** log a message (skip threshold_level check) */ void append(ft_log_event & event); public: /** return root logger */ static ft_log & get_root_logger(); /** find or create a logger by name */ static ft_log & get_logger(const ft_mstring & logger_name); /** log a message (unless its level is suppressed) */ void log(ft_log_event & event); /** return true if level is enabled (i.e. not suppressed) for this logger. */ FT_INLINE bool is_enabled(ft_log_level level) const { return level >= get_threshold_level(); } /** get logger name. */ FT_INLINE const ft_mstring & get_name() const { return * name; } /** return the level, i.e. least serious level that is not suppressed. */ FT_INLINE ft_log_level get_level() const { return level; } /** return the effective level: if level is set return it, otherwise return parent effective level. */ ft_log_level get_effective_level() const; /** return the threshold level: the minimum of this and all ancestor's levels. */ ft_log_level get_threshold_level() const; /** set the level, i.e. least serious level that is not suppressed. */ FT_INLINE void set_level(ft_log_level level) { this->level = level; invalidate_all_cached_levels(); } /** add an appender */ void add_appender(ft_log_appender & appender); /** remove an appender */ void remove_appender(ft_log_appender & appender); }; FT_NAMESPACE_END #endif /* FSTRANSFORM_LOG_HH */ fstransform-0.9.4/fsremap/src/main.cc000066400000000000000000000177361345021500300175560ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * main.cc * * Created on: Mar 1, 2011 * Author: max */ #include "first.hh" #undef FR_TEST_MAP #undef FR_TEST_MAP_MERGE #undef FR_TEST_VECTOR_COMPOSE #undef FR_TEST_RANDOM #undef FR_TEST_IOCTL_FIEMAP #undef FR_TEST_WRITE_ZEROES #undef FR_TEST_PRETTY_TIME #if defined(FR_TEST_MAP) # include "map.hh" # include "work.hh" FT_NAMESPACE_BEGIN #define FR_MAIN(argc, argv) FT_NS test_map() template static int test_map() { fr_map map; map.insert(3, 3, 1, FC_DEFAULT_USER_DATA); map.insert(0, 0, 3, FC_DEFAULT_USER_DATA); fr_work::show("test map", "", 1, map, FC_INFO); return 0; } FT_NAMESPACE_END #elif defined(FR_TEST_MAP_MERGE) #include "log.hh" #include "map.hh" #include "vector.hh" FT_NAMESPACE_BEGIN template static void test_show(const char * label1, const char * label2, const fr_vector v) { v.show(label1, label2, 1, FC_INFO); } #define FR_MAIN(argc, argv) FT_NS test_map_merge() template static int test_map_merge() { fr_vector v1, v2; v1.append(39174144, 4589568, 31744, FC_DEFAULT_USER_DATA); v2.append(70565888, 4476928, 114688, FC_DEFAULT_USER_DATA); test_show("v1", "", v1); test_show("v2", "", v2); // use fr_map::merge_shift() to merge. // unluckily it merges based on ->physical, so we must transpose the vectors v1.transpose(); v2.transpose(); fr_map map; enum { NO_SHIFT = 0 }; map.append0_shift(v1, NO_SHIFT); map.merge_shift(v2, NO_SHIFT, FC_PHYSICAL1); v1.assign(map.begin(), map.end()); v1.transpose(); test_show("v1", " after merge", v1); return 0; } FT_NAMESPACE_END #elif defined(FR_TEST_VECTOR_COMPOSE) #include "log.hh" #include "vector.hh" FT_NAMESPACE_BEGIN template static void test_show(const char * label, const fr_vector v) { v.show(label, "", 1, FC_INFO); } #define FR_MAIN(argc, argv) FT_NS test_vector_compose() template static int test_vector_compose() { fr_vector v1, v2, result, unmapped; T bitmask = 0; v1.append( 0, 10,100, FC_DEFAULT_USER_DATA); v2.append( 4, 0, 30, FC_DEFAULT_USER_DATA); v2.append(54, 30, 50, FC_DEFAULT_USER_DATA); v2.append(94, 80, 40, FC_DEFAULT_USER_DATA); int err = result.compose(v1, v2, bitmask, unmapped); if (err == 0) { ff_log(FC_INFO, 0, "block_size_bitmask = 0x%" FT_XLL, (ft_ull) bitmask); test_show("result", result); test_show("unmapped", unmapped); } return err ? 1 : 0; } FT_NAMESPACE_END #elif defined(FR_TEST_RANDOM) # include "assert.hh" # include "log.hh" # include "misc.hh" FT_NAMESPACE_BEGIN #define FR_MAIN(argc, argv) FT_NS test_random(argc, argv) static int test_random(int argc, char ** argv) { ft_ull i, n = 1000, max = 7; if (argc > 1) ff_str2ull(argv[1], & max); if (argc > 2) ff_str2ull(argv[2], & n); if (max > 0x10000) { for (i = 0; i < n; i++) ff_log(FC_INFO, 0, "ff_random(%20" FT_ULL ") = %20" FT_ULL , max, ff_random(max)); } else { ft_ull r; ft_size * hist = new ft_size[max + 1]; for (i = 0; i <= max; i++) hist[i] = 0; for (i = 0; i < n; i++) { r = ff_random(max); ff_assert(r <= max); ++hist[r]; } for (i = 0; i <= max; i++) ff_log(FC_INFO, 0, "histogram[%" FT_ULL "] = %" FT_ULL , i, (ft_ull)hist[i]); delete[] hist; } return 0; } FT_NAMESPACE_END #elif defined(FR_TEST_IOCTL_FIEMAP) # include "log.hh" # include "vector.hh" # include "io/extent_posix.hh" # include "io/util_posix.hh" #include #include #include #include #include FT_NAMESPACE_BEGIN using FT_IO_NS ff_posix_size; using FT_IO_NS ff_read_extents_posix; #define FR_MAIN(argc, argv) FT_NS test_ioctl_fiemap(argc, argv) static int test_ioctl_fiemap(int argc, char ** argv) { ft_log::get_root_logger().set_level(FC_DEBUG); ft_log_appender::redefine(stdout, FC_FMT_DATETIME_LEVEL_CALLER_MSG, FC_DEBUG, FC_NOTICE); ft_log_appender::redefine(stderr, FC_FMT_DATETIME_LEVEL_CALLER_MSG, FC_WARN); fr_vector extents; ft_uoff dev_size = 0x7FFFFFFFul, block_size_bitmask; const char * path; int fd, err = 0; while ((path = * ++argv) != NULL) { if ((fd = ::open(path, O_RDONLY)) < 0) { err = ff_log(FC_ERROR, errno, "error opening file '%s'", path); break; } extents.clear(); block_size_bitmask = 0; if ((err = ff_read_extents_posix(fd, dev_size, extents, block_size_bitmask)) != 0) break; ft_size n = extents.size(); ff_log(FC_INFO, 0, "# %4" FT_ULL " extent%s in %s", (ft_ull) n, (n == 1 ? " " : "s"), path); ff_log(FC_INFO, 0, "# extent physical logical length user_data"); for (ft_size i = 0; i < n; i++) { fr_extent & e = extents[i]; ff_log(FC_INFO, 0, "#%8" FT_ULL "\t%12" FT_ULL "\t%12" FT_ULL "\t%8" FT_ULL "\t(%" FT_ULL ")", (ft_ull)i, (ft_ull) e.physical(), (ft_ull) e.logical(), (ft_ull) e.length(), (ft_ull) e.user_data()); } } return err; } FT_NAMESPACE_END #elif defined(FR_TEST_WRITE_ZEROES) FT_IO_NAMESPACE_BEGIN int ff_zero_loop_file_holes(int argc, char ** argv); FT_IO_NAMESPACE_END # define FR_MAIN(argc, argv) FT_IO_NS ff_zero_loop_file_holes(argc, argv) #elif defined(FR_TEST_PRETTY_TIME) #include "misc.hh" #include "log.hh" FT_NAMESPACE_BEGIN int ff_test_pretty_time(int argc, char ** argv) { ft_log_level log_level = FT_NS FC_INFO; double time, percentage = 0.0, pretty_len = 0; const char * simul_msg = "", * pretty_label = ""; for (time = 0.4; time < 800000000.0; time *= 1.1) { ft_ull time_left1 = 0, time_left2 = 0; const char * time_left_label1 = NULL, * time_left_label2 = NULL; ff_pretty_time2(time, & time_left1, & time_left_label1, & time_left2, & time_left_label2); /* we write something like "1 hour and 20 minutes" instead of just "1 hour" or "1.3 hours" */ if (time_left_label2 != NULL) { ff_log(log_level, 0, "%sprogress: %4.1f%% done, %.2f %sbytes still to relocate, estimated %" FT_ULL " %s%s and %" FT_ULL " %s%s left", simul_msg, percentage, pretty_len, pretty_label, time_left1, time_left_label1, (time_left1 != 1 ? "s": ""), time_left2, time_left_label2, (time_left2 != 1 ? "s": "")); } else { ff_log(log_level, 0, "%sprogress: %4.1f%% done, %.2f %sbytes still to relocate, estimated %" FT_ULL " %s%s left", simul_msg, percentage, pretty_len, pretty_label, time_left1, time_left_label1, (time_left1 != 1 ? "s": "")); } } return 0; } FT_NAMESPACE_END # define FR_MAIN(argc, argv) FT_NS ff_test_pretty_time(argc, argv) #else /* actual fstranform program */ # include "remap.hh" // for fr_remap # define FR_MAIN(argc, argv) FT_NS fr_remap::main(argc, argv) #endif /* defined(FT_TEST_*) */ int main(int argc, char ** argv) { return FR_MAIN(argc, argv); } fstransform-0.9.4/fsremap/src/map.cc000066400000000000000000000022011345021500300173640ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * map.cc * * Created on: Feb 27, 2011 * Author: max */ #include "first.hh" // for FT_*TEMPLATE* macros */ #ifdef FT_HAVE_EXTERN_TEMPLATE # include "map.t.hh" FT_TEMPLATE_INSTANTIATE(FT_TEMPLATE_map_hh) #endif /* FT_HAVE_EXTERN_TEMPLATE */ fstransform-0.9.4/fsremap/src/map.hh000066400000000000000000000331641345021500300174120ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * map.hh * * Created on: Feb 27, 2011 * Author: max */ #ifndef FSREMAP_MAP_HH #define FSREMAP_MAP_HH #include "check.hh" #include // for std::map #include "types.hh" // for ft_uoff #include "fwd.hh" // for fr_map and fr_vector forward declarations #include "log.hh" // for ft_log_level, FC_SHOW_DEFAULT_LEVEL. also used by map.t.hh for ff_log() #include "extent.hh" // for fr_extent_key, fr_extent_payload, ft_match FT_NAMESPACE_BEGIN template class fr_map : private std::map, fr_extent_payload > { private: typedef std::map, fr_extent_payload > super_type; public: typedef typename super_type::key_type key_type; typedef typename super_type::mapped_type mapped_type; typedef typename super_type::value_type value_type; typedef typename super_type::iterator iterator; typedef typename super_type::const_iterator const_iterator; private: /** compare two key+value extents and find relative position */ static fr_extent_relation compare(const_iterator pos1, const_iterator pos2); /** compare two key+value extents and find relative position */ static fr_extent_relation compare(const_iterator pos1, const key_type & key2, const mapped_type & value2); /** compare two key+value extents and find relative position */ static fr_extent_relation compare(const key_type & key1, const mapped_type & value1, const key_type & key2, const mapped_type & value2); /** * add a single extent the fr_map, hinting that insertion is at map end * * does not merge and does not check for merges */ void append0(T physical, T logical, T length, ft_size user_data); /** * merge extent (which can belong to this fr_map) into specified position. * the two extents MUST exactly touch! * i.e. their fr_extent_relation MUST be either FC_EXTENT_TOUCH_BEFORE or FC_EXTENT_TOUCH_AFTER * * return iterator to merged position. * * this is an internal method and should ONLY be invoked by merge(), * as it does not handle chains of merges, as merge() does instead. * Again: call merge(), not this method. */ iterator merge0(iterator pos1, const key_type & key2, const mapped_type & value2); /** * merge together two extents (which must belong to this fr_map). * the two extents MUST exactly touch! * i.e. their fr_extent_relation MUST be either FC_EXTENT_TOUCH_BEFORE or FC_EXTENT_TOUCH_AFTER * * return iterator to merged position. * * this is an internal method and should ONLY be invoked by merge(), * as it does not handle chains of merges, as merge() does instead. * Again: call merge(), not this method. * * this method exists because it is simpler to implement than * merge0(iterator, const key_type &, const mapped_type &) */ iterator merge0(iterator pos1, iterator pos2); /** * merge extent (which must NOT belong to this fr_map) into specified fr_map position. * the two extents MUST exactly touch! * i.e. their fr_extent_relation MUST be either FC_EXTENT_TOUCH_BEFORE or FC_EXTENT_TOUCH_AFTER * * return iterator to merged position. * * this method automatically performs chain of merges if needed: * for example, if extent 2 is merged in a fr_map containing 0..1 and 3..5, * this method will first merge 0..1 with 2, obtaining 0..2, * then it will realize that result can be merged with 3..5 * and it will also perform this second merging, obtaining 0..5 */ iterator merge(iterator pos1, const key_type & key2, const mapped_type & value2); /** * remove a part of an existing extent (or a whole existing extent) * from this fr_map, splitting the existing extent if needed. * throws an assertion failure if extent to remove is not part of existing extents. * * does not support removing an extent that is part of TWO OR MORE existing extents. */ void remove1(const value_type & extent, ft_match match); public: // construct empty fr_map fr_map(); // duplicate a fr_map, i.e. initialize this fr_map as a copy of other. fr_map(const fr_map & other); // destroy fr_map ~fr_map(); // return iterator to beginning of this map using super_type::begin; // return iterator one past the end of this map using super_type::end; // return true is this map is empty, i.e. if it size() == 0 using super_type::empty; // return number of extents in this map using super_type::size; // clear this map, i.e. erase all elements using super_type::clear; // find an extent given its starting ->physical using super_type::find; // copy fr_map, i.e. set this fr_map contents as a copy of other's contents. const fr_map & operator=(const fr_map & other); // swap this map contents with other map void swap(fr_map & other); /** * returns the minimum physical and the maximum physical+length in this map. * if this map is empty, return {0,0} */ void bounds(key_type & min_key, key_type & max_key) const; /** * find the intersection (matching physical) * between the specified single block and this map, and store the intersection in ret_extent. * if no intersections, return false and ret_extent will be unchanged. */ bool find_physical_block(T key_physical, value_type & ret_extent) const; /** * find the intersection (matching physical, or both physical and logical) * between the two specified extents, insert it into this map and return true. * if no intersections, return false and this will be unchanged * * note: if the intersection is only physical, * the intersection will contain the appropriate subrange of extent[match] -> logical */ bool intersect(const value_type & extent1, const value_type & extent2, ft_match match); /** * find the intersections (matching physical, or both physical and logical) * between specified map and extent. * insert list of intersections into this map and return true. * if no intersections, return false and this will be unchanged * * note: if the intersection is only physical, * the intersection will contain the appropriate subrange of {map1,extent2}[match] -> logical */ bool intersect_all(const fr_map & map1, const value_type & extent2, ft_match match); /** * find the intersections (matching physical, or both physical and logical) * between specified map1 and map2. * insert list of intersections into this map and return true. * if no intersections, return false and this map will be unchanged * * note: if the intersection is only physical, * the intersection will contain the appropriate subrange of map[match] -> logical */ bool intersect_all_all(const fr_map & map1, const fr_map & map2, ft_match match); /** * add a single extent the fr_map * * use with extreme caution, it does NOT merge and does NOT CHECK for merges */ void insert0(const key_type & key, const mapped_type & value); /** * add a single extent the fr_map * * use with extreme caution, it does NOT merge and does NOT CHECK for merges */ void insert0(T physical, T logical, T length, ft_size user_data); /** * insert a single extent into this fr_map, * merging with existing extents where possible. * return iterator to inserted/merged extent */ iterator insert(const key_type & key, const mapped_type & value); /** * insert a single extent into this fr_map, * merging with existing extents where possible. * return iterator to inserted/merged extent * * simply calls insert(key_type, value_type) */ FT_INLINE iterator insert(const value_type & extent) { return insert(extent.first, extent.second); } /** * insert a single extent into this fr_map, * merging with existing extents where possible. * return iterator to inserted/merged extent. * * simply calls insert(key_type, value_type) */ iterator insert(T physical, T logical, T length, ft_size user_data); /** insert a list of extents into this fr_map, merging where possible. */ template void insert_all(const_iter iter, const_iter end) { for (; iter != end; ++iter) insert(*iter); } /** insert another extents map into this fr_map, merging where possible. */ void insert_all(const fr_map & map); /** * remove an existing extent from this fr_map. * no need to check for splitting in this method, as it cannot happen: * the extent to remove is specified by its iterator, * so it must be exactly one of the extents of this map */ void remove(iterator iter); /** * remove a part of an existing extent (or one or more existing extents) * from this fr_map, splitting the existing extents if needed. */ void remove(const value_type & extent, ft_match match = FC_BOTH); /** * remove a part of an existing extent (or one or more existing extents) * from this fr_map, splitting the existing extents if needed. */ void remove(T physical, T logical, T length, ft_match match = FC_BOTH); /** * remove any (partial or full) intersection with existing extents from this fr_map, * splitting the existing extents if needed. */ template void remove_all(const_iter iter, const_iter end, ft_match match = FC_BOTH) { for (; iter != end; ++iter) remove(*iter, match); } /** * remove any (partial or full) intersection with existing extents from this fr_map, * splitting the existing extents if needed. */ void remove_all(const fr_map & map, ft_match match = FC_BOTH); /** * remove an initial part of an existing extent from this fr_map. * returns iterator to new, smaller extent, or end() if the whole extent was removed */ iterator remove_front(iterator iter, T shrink_length); /** * set this map to a transposed copy of other map, * i.e. to a copy where all ->physical and ->logical are swapped */ void transpose(const fr_map & other); /** * insert the whole other vector into this map, * shifting extents by effective_block_size_log2, * and hinting that insertion is at map end. * optimized assuming that 'other' is sorted by physical. * * does not merge and does not check for merges * does not check for overflows */ void append0_shift(const fr_vector & other, ft_uoff effective_block_size_log2); /** * shift and merge specified extent vector * into this map, skipping any intersection. */ void merge_shift(const fr_vector & other, ft_uoff effective_block_size_log2, ft_match match); /** * makes the physical complement of 'other' vector, * i.e. calculates the physical extents NOT used in 'other' vector, * shifts them by effective_block_size_log2, * and inserts it in this map. * * since the file(s) contained in such complementary extents are not known, * all calculated extents will have ->logical == ->physical. * * 'other' must be already sorted by physical! * does not merge and does not check for merges * does not check for overflows */ void complement0_physical_shift(const fr_vector & other, ft_uoff effective_block_size_log2, ft_uoff device_length); /** * makes the logical complement of 'other' vector, * i.e. calculates the logical extents NOT used in 'other' vector, * shifts them by effective_block_size_log2, * and inserts it in this map. * * since the file(s) contained in such complementary extents are not known, * all calculated extents will have ->logical == ->physical. * * 'other' must be already sorted by logical! * does not merge and does not check for merges * does not check for overflows */ void complement0_logical_shift(const fr_vector & other, ft_uoff effective_block_size_log2, ft_uoff device_length); /** print map contents to log */ void show(const char * label1, const char * label2, ft_uoff effective_block_size, ft_log_level level = FC_SHOW_DEFAULT_LEVEL) const; }; FT_NAMESPACE_END #ifdef FT_HAVE_EXTERN_TEMPLATE # define FT_TEMPLATE_map_hh(ft_prefix, T) ft_prefix class FT_NS fr_map< T >; FT_TEMPLATE_DECLARE(FT_TEMPLATE_map_hh) #else # include "map.t.hh" #endif /* FT_HAVE_EXTERN_TEMPLATE */ #endif /* FSREMAP_MAP_HH */ fstransform-0.9.4/fsremap/src/map.t.hh000066400000000000000000000723671345021500300176640ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * map.t.hh * * Created on: Feb 27, 2011 * Author: max */ #include "first.hh" #include "assert.hh" // for ff_assert macro #include "map.hh" // for fr_map #include "misc.hh" // for ff_max2(), ff_min2() #include "vector.hh" // for fr_vector FT_NAMESPACE_BEGIN #define ff_map_assert ff_assert // construct empty fr_map template fr_map::fr_map() : super_type() { } // duplicate a fr_map, i.e. initialize this fr_map as a copy of other. template fr_map::fr_map(const fr_map & other) : super_type(other) { } // destroy fr_map template fr_map::~fr_map() { } /** compare two key+value extents and find relative position */ template fr_extent_relation fr_map::compare(const_iterator pos1, const_iterator pos2) { return compare(pos1->first, pos1->second, pos2->first, pos2->second); } /** compare two key+value extents and find relative position */ template fr_extent_relation fr_map::compare(const_iterator pos1, const key_type & key2, const mapped_type & value2) { return compare(pos1->first, pos1->second, key2, value2); } /** compare two key+value extents and find relative position */ template fr_extent_relation fr_map::compare(const key_type & key1, const mapped_type & value1, const key_type & key2, const mapped_type & value2) { T physical1 = key1.physical, logical1 = value1.logical, length1 = value1.length; T physical2 = key2.physical, logical2 = value2.logical, length2 = value2.length; ft_size user_data1 = value1.user_data; ft_size user_data2 = value2.user_data; fr_extent_relation rel; if (physical1 < physical2) { if (physical1 + length1 == physical2 && logical1 + length1 == logical2 && user_data1 == user_data2) rel = FC_EXTENT_TOUCH_BEFORE; else if (physical1 + length1 <= physical2) rel = FC_EXTENT_BEFORE; else rel = FC_EXTENT_INTERSECT; } else if (physical1 == physical2) { rel = FC_EXTENT_INTERSECT; } else /* physical1 > physical2 */ { if (physical1 == physical2 + length2 && logical1 == logical2 + length2 && user_data1 == user_data2) rel = FC_EXTENT_TOUCH_AFTER; else if (physical2 + length2 <= physical1) rel = FC_EXTENT_BEFORE; else rel = FC_EXTENT_INTERSECT; } return rel; } /** * merge extent (which can belong to this fr_map) into specified position. * the two extents MUST exactly touch! * i.e. their fr_extent_relation MUST be either FC_EXTENT_TOUCH_BEFORE or FC_EXTENT_TOUCH_AFTER * * return iterator to merged position. * * this is an internal method and should ONLY be invoked by merge(), * as it does not handle chains of merges, as merge() does instead. * Again: call merge(), not this method. */ template typename fr_map::iterator fr_map::merge0(iterator pos1, const key_type & key2, const mapped_type & value2) { fr_extent_relation rel = compare(pos1, key2, value2); const key_type & key1 = pos1->first; mapped_type & value1 = pos1->second; // modify extent in-place value1.length += value2.length; if (rel == FC_EXTENT_TOUCH_BEFORE) { // nothing to do } else if (rel == FC_EXTENT_TOUCH_AFTER) { // modify extent_key in-place. possible, since we defined fr_extent_key::physical as 'mutable' key1.physical = key2.physical; value1.logical = value2.logical; } else { /* must not happen! trigger an assertion failure. */ ff_map_assert(rel == FC_EXTENT_TOUCH_BEFORE || rel == FC_EXTENT_TOUCH_AFTER); } return pos1; } /** * merge together two extents (which must belong to this fr_map). * the two extents MUST exactly touch! * i.e. their fr_extent_relation MUST be either FC_EXTENT_TOUCH_BEFORE or FC_EXTENT_TOUCH_AFTER * * return iterator to merged position. * * this is an internal method and should ONLY be invoked by merge(), * as it does not handle chains of merges, as merge() does instead. * Again: call merge(), not this method. * * this method exists because it is simpler to implement than * merge0(iterator, const key_type &, const mapped_type &) */ template typename fr_map::iterator fr_map::merge0(iterator pos1, iterator pos2) { fr_extent_relation rel = compare(pos1, pos2); mapped_type & value1 = pos1->second; mapped_type & value2 = pos2->second; T length = value1.length + value2.length; if (rel == FC_EXTENT_TOUCH_BEFORE) { // modify first extent in-place, erase second value1.length = length; super_type::erase(pos2); return pos1; } else if (rel == FC_EXTENT_TOUCH_AFTER) { // modify second extent in-place, erase first value2.length = length; super_type::erase(pos1); return pos2; } else { /* must not happen! trigger an assertion failure. */ ff_map_assert(rel == FC_EXTENT_TOUCH_BEFORE || rel == FC_EXTENT_TOUCH_AFTER); } return pos1; } /** * merge extent (which must NOT belong to this fr_map) into specified fr_map position. * the two extents MUST exactly touch! * i.e. their fr_extent_relation MUST be either FC_EXTENT_TOUCH_BEFORE or FC_EXTENT_TOUCH_AFTER * * return iterator to merged position. * * this method automatically performs chain of merges if needed: * for example, if extent 2 is merged in a fr_map containing 0..1 and 3..5, * this method will first merge 0..1 with 2, obtaining 0..2, * then it will realize that result can be merged with 3..5 * and it will also perform this second merging, obtaining 0..5 */ template typename fr_map::iterator fr_map::merge(iterator pos1, const key_type & key2, const mapped_type & value2) { fr_extent_relation rel = compare(pos1, key2, value2); if (rel == FC_EXTENT_TOUCH_BEFORE) { pos1 = merge0(pos1, key2, value2); /* check for further possible merges! */ if (pos1 != begin()) { iterator prev = pos1; --prev; if (compare(prev, pos1) == FC_EXTENT_TOUCH_BEFORE) pos1 = merge0(prev, pos1); } } else if (rel == FC_EXTENT_TOUCH_AFTER) { pos1 = merge0(pos1, key2, value2); /* check for further possible merges! */ iterator next = pos1; ++next; if (next != end()) { if (compare(pos1, next) == FC_EXTENT_TOUCH_BEFORE) pos1 = merge0(pos1, next); } } else { /* must not happen! trigger an assertion failure. */ ff_assert(rel == FC_EXTENT_TOUCH_BEFORE || rel == FC_EXTENT_TOUCH_AFTER); } return pos1; } // copy fr_map, i.e. set this fr_map contents as a copy of other's contents. template const fr_map & fr_map::operator=(const fr_map & other) { super_type::operator=(other); return * this; } // swap this map contents with other map template void fr_map::swap(fr_map & other) { super_type::swap(other); } /** * returns the minimum physical and the maximum physical+length in this map. * if this map is empty, return {0,0} */ template void fr_map::bounds(key_type & min_key, key_type & max_key) const { const_iterator b = begin(), e = end(); if (b != e) { min_key.physical = b->first.physical; --e; max_key.physical = e->first.physical + e->second.length; } else min_key.physical = max_key.physical = 0; } /** * find the intersection (matching physical) * between the specified single block and this map, and store the intersection in ret_extent. * if no intersections, return false and ret_extent will be unchanged. */ template bool fr_map::find_physical_block(T key_physical, value_type & ret_extent) const { if (empty()) return false; key_type key; key.physical = key_physical; /* iterator to first element >= key */ const_iterator iter = this->lower_bound(key), e = end(); if (iter == e) --iter; const value_type & extent1 = *iter; T physical1 = extent1.first.physical; T logical1 = extent1.second.logical; T end1 = physical1 + extent1.second.length; if (key_physical < physical1 || key_physical >= end1) return false; ret_extent.first.physical = key_physical; ret_extent.second.logical = logical1 + (key_physical - physical1); ret_extent.second.length = 1; ret_extent.second.user_data = extent1.second.user_data; return true; } /** * find the intersection (matching physical, or both physical and logical) between the two specified extents, * insert it into 'result' (with user_data = FC_DEFAULT_USER_DATA) and return true. * if no intersections, return false and 'result' will be unchanged. * * note: if the intersection is only physical, * the intersection will contain the appropriate subrange of extent[which] -> logical */ template bool fr_map::intersect(const value_type & extent1, const value_type & extent2, ft_match match) { const key_type & key1 = extent1.first; const mapped_type & value1 = extent1.second; T physical1 = key1.physical; T logical1 = value1.logical; T end1 = physical1 + value1.length; const key_type & key2 = extent2.first; const mapped_type & value2 = extent2.second; T physical2 = key2.physical; T logical2 = value2.logical; T end2 = physical2 + value2.length; key_type key = { 0 }; mapped_type value = { 0, 0, (match == FC_PHYSICAL2 ? extent2 : extent1).second.user_data }; switch (match) { case FC_PHYSICAL1: case FC_PHYSICAL2: if (end1 > physical2 && physical1 < end2) { key.physical = ff_max2(physical1, physical2); value.logical = match == FC_PHYSICAL1 ? logical1 + (key.physical - physical1) : logical2 + (key.physical - physical2); value.length = ff_min2(end1, end2) - key.physical; } else return false; break; case FC_BOTH: if (end1 > physical2 && physical1 < end2 && logical2 - logical1 == physical2 - physical1) { key.physical = ff_max2(physical1, physical2); value.logical = ff_max2(logical1, logical2); value.length = ff_min2(end1, end2) - key.physical; } else return false; break; default: return false; } /* * insert the intersection in this map, but do NOT try to merge it. * merges must NOT be performed because this->remove() and this->remove1() * expect intersections to be subsets of extents they come from */ this->insert0(key, value); return true; } /** * find the intersections (matching physical, or both physical and logical) between specified map and extent. * insert list of intersections into this and return true. * if no intersections, return false and this will be unchanged * * note: if the intersection is only physical, * the intersection will contain the appropriate subrange of {map,extent}[which] -> logical */ template bool fr_map::intersect_all(const fr_map & map, const value_type & extent, ft_match match) { const key_type & key1 = extent.first; const_iterator pos = map.super_type::upper_bound(key1), begin = map.begin(), end = map.end(); bool ret = false; if (pos != begin) { --pos; /* pos is now last extent starting before key */ ret |= intersect(*pos, extent, match); ++pos; } for (; pos != end; ++pos) { if (intersect(*pos, extent, match)) ret = true; else break; } return ret; } /** * find the intersections (matching physical, or both physical and logical) between specified map1 and map2. * insert list of intersections into this map and return true. * if no intersections, return false and this map will be unchanged * * note: if the intersection is only physical, * the intersection will contain the appropriate subrange of map[match] -> logical */ template bool fr_map::intersect_all_all(const fr_map & map1, const fr_map & map2, ft_match match) { ft_size size1 = map1.size(), size2 = map2.size(); if (size1 == 0 || size2 == 0) return false; const fr_map & map_iterate = size1 < size2 ? map1 : map2; const fr_map & map_other = size1 < size2 ? map2 : map1; if (size1 < size2) match = ff_match_transpose(match); key_type bound_lo, bound_hi; map_other.bounds(bound_lo, bound_hi); const_iterator iter = map_iterate.super_type::upper_bound(bound_lo), end = map_iterate.super_type::lower_bound(bound_hi); if (iter != map_iterate.begin()) /* iter is now last position less than bound_lo */ --iter; bool ret = false; for (; iter != end; ++iter) ret |= intersect_all(map_other, *iter, match); return ret; } /** * add a single extent to the fr_map, * merging with existing extents where possible */ template typename fr_map::iterator fr_map::insert(const key_type & key, const mapped_type & value) { /* * pos = "next" extent, i.e. * first extent greater than or equal to this key, * or end() if no such extent exists */ iterator pos = super_type::lower_bound(key); fr_extent_relation rel; if (pos != end()) { // check if extent to be added intersects or touches "next" extent rel = compare(pos, key, value); if (rel == FC_EXTENT_TOUCH_BEFORE || rel == FC_EXTENT_TOUCH_AFTER) return merge(pos, key, value); } if (pos != begin()) { // check if extent to be added intersects or touches "previous" extent --pos; rel = compare(pos, key, value); if (rel == FC_EXTENT_TOUCH_BEFORE || rel == FC_EXTENT_TOUCH_AFTER) return merge(pos, key, value); ++pos; } // just insert the key/value pair return super_type::insert(pos, std::make_pair(key, value)); } /** * insert a single extent into this fr_map, * merging with existing extents where possible. * return iterator to inserted/merged extent */ template typename fr_map::iterator fr_map::insert(T physical, T logical, T length, ft_size user_data) { key_type key = { physical }; mapped_type value = { logical, length, user_data }; return insert(key, value); } /** insert another extents map into this fr_map, merging where possible. */ template void fr_map::insert_all(const fr_map & map) { insert_all(map.begin(), map.end()); } /** * remove a part of an existing extent (or a whole existing extent) * from this fr_map, splitting the existing extent if needed. * throws an assertion failure if extent to remove is not part of existing extents. * * does not support removing an extent that is part of TWO OR MORE existing extents. */ template void fr_map::remove1(const value_type & extent, ft_match match) { ff_assert(!empty()); const key_type & key = extent.first; const mapped_type & value = extent.second; /* * pos = "next" extent, i.e. first extent greater than key to remove, * or end() if no such extent exists */ iterator pos = super_type::upper_bound(key); ff_assert(pos != begin()); /* * go back one place. pos will now be "prev", * i.e. the last extent lesser than or equal to key to remove */ --pos; const key_type & last_key = pos->first; mapped_type & last_payload = pos->second; T last_physical = last_key.physical; T last_logical = last_payload.logical; T last_length = last_payload.length; ft_size user_data = last_payload.user_data; T physical = key.physical; T logical = value.logical; T length = value.length; ff_assert(last_physical <= physical); if (match == FC_BOTH) { ff_assert(last_logical <= logical); /* also logical to remove must match */ ff_assert(physical - last_physical == logical - last_logical); } /* last must finish together or after extent to remove */ ff_assert(last_physical + last_length >= physical + length); /* let's consider extents start points */ if (last_physical < physical) { /* first case: * "last" existing extent starts before extent to remove * +------------ * | to_remove * +-+------------ * | last extent * +-------------- */ last_payload.length = physical - last_physical; } else { /* second case: * "last" existing extent starts together with extent to remove * +-------------- * | to_remove * +-------------- * | last extent * +-------------- */ super_type::erase(pos); } /* 2) let's consider extents end points */ if (last_physical + last_length > physical + length) { /* if "last" existing extent ends after extent to remove * then we need to insert the remainder of last extent * -----------+ * to_remove | * -----------+-+ * last extent | * -------------+ */ T new_physical = physical + length; T new_logical = logical + length; T new_length = last_physical + last_length - new_physical; insert0(new_physical, new_logical, new_length, user_data); } else { /* nothing to do */ } } /** * remove an existing extent from this fr_map. * no need to check for splitting in this method, as it cannot happen: * the extent to remove is specified by its iterator, * so it must be exactly one of the extents of this map */ template void fr_map::remove(iterator iter) { super_type::erase(iter); } /** * remove a part of an existing extent (or one or more existing extents) * from this fr_map, splitting the existing extents if needed. */ template void fr_map::remove(const value_type & extent, ft_match match) { fr_map intersect_list; intersect_list.intersect_all(*this, extent, match); const_iterator iter = intersect_list.begin(), end = intersect_list.end(); for (; iter != end; ++iter) remove1(*iter, match); } /** * remove a part of an existing extent (or one or more existing extents) * from this fr_map, splitting the existing extents if needed. */ template void fr_map::remove(T physical, T logical, T length, ft_match match) { key_type key = { physical }; mapped_type value = { logical, length, FC_DEFAULT_USER_DATA }; value_type extent(key, value); remove(extent, match); } /** * remove any (partial or full) intersection with existing extents from this fr_map, * splitting the existing extents if needed. */ template void fr_map::remove_all(const fr_map & map, ft_match match) { if (this == & map) { clear(); return; } key_type bound_lo, bound_hi; bounds(bound_lo, bound_hi); const_iterator iter = map.super_type::upper_bound(bound_lo), end = map.super_type::lower_bound(bound_hi); if (iter != map.begin()) --iter; remove_all(iter, end, match); } /** * remove an initial part of an existing extent from this fr_map. * returns iterator to new, smaller extent, or end() if the whole extent was removed */ template typename fr_map::iterator fr_map::remove_front(iterator iter, T shrink_length) { ff_assert(iter != end()); value_type & extent = *iter; const key_type & key = extent.first; mapped_type & value = extent.second; T length = value.length; ff_assert(length >= shrink_length); if (length == shrink_length) { super_type::erase(iter); return end(); } /** modify the extent in-place */ key.physical += shrink_length; /* key_type::physical is mutable :) */ value.logical += shrink_length; value.length -= shrink_length; return iter; } /** * set this map to a transposed copy of other map, * i.e. to a copy where all ->physical and ->logical are swapped */ template void fr_map::transpose(const fr_map & other) { clear(); const_iterator iter = other.begin(), end = other.end(); for (; iter != end; ++iter) { const value_type & extent = *iter; insert0(extent.second.logical, extent.first.physical, extent.second.length, extent.second.user_data); } } /** * add a single extent the fr_map * * does not merge and does not check for merges */ template void fr_map::insert0(T physical, T logical, T length, ft_size user_data) { key_type key = { physical }; mapped_type & value = (*this)[key]; value.logical = logical; value.length = length; value.user_data = user_data; } /** * add a single extent the fr_map * * does not merge and does not check for merges */ template void fr_map::insert0(const key_type & key, const mapped_type & value) { mapped_type & value_ = (*this)[key]; value_ = value; /* struct assignment: copy logical, length and user_data */ } /** * insert a single extent the fr_map, hinting that insertion is at map end * * does not merge and does not check for merges */ template void fr_map::append0(T physical, T logical, T length, ft_size user_data) { key_type key = { physical }; mapped_type value = { logical, length, user_data }; value_type extent(key, value); super_type::insert(end(), extent); } /** * insert the whole other vector into this map, * shifting extents by effective_block_size_log2, * and hinting that insertion is at map end. * optimized assuming that 'other' is sorted by physical. * * does not merge and does not check for merges * does not check for overflows */ template void fr_map::append0_shift(const fr_vector & other, ft_uoff effective_block_size_log2) { typename fr_vector::const_iterator iter = other.begin(), end = other.end(); for (; iter != end; ++iter) { const fr_extent & extent = * iter; append0(extent.physical() >> effective_block_size_log2, extent.logical() >> effective_block_size_log2, extent.length() >> effective_block_size_log2, extent.user_data()); } } /** * shift and merge specified extent vector * into this map, skipping any intersection. */ template void fr_map::merge_shift(const fr_vector & other, ft_uoff effective_block_size_log2, ft_match match) { if (other.empty()) { // nothing to do } else if (this->empty()) { // easy this->append0_shift(other, effective_block_size_log2); } else { fr_map other_map; other_map.append0_shift(other, effective_block_size_log2); // delete the intersection between this and other if (match == FC_PHYSICAL1) other_map.remove_all(* this, FC_PHYSICAL2); else this->remove_all(other_map, FC_PHYSICAL2); // insert the remainder into this this->insert_all(other_map); } } /** * makes the physical complement of 'other' vector, * i.e. calculates the physical extents NOT used in 'other' vector, * shifts them by effective_block_size_log2, * and inserts it in this map (with user_data = FC_DEFAULT_USER_DATA) * * since the file(s) contained in such complementary extents are not known, * all calculated extents will have ->logical == ->physical. * * 'other' must be already sorted by physical! * does not merge and does not check for merges * does not check for overflows */ template void fr_map::complement0_physical_shift(const fr_vector & other, ft_uoff effective_block_size_log2, ft_uoff device_length) { T physical, last; ft_size i, n = other.size(); if (empty()) last = 0; else { const value_type & back = *--this->end(); last = back.first.physical + back.second.length; } /* loop on 'other' extents */ for (i = 0; i < n; i++) { const fr_extent & curr = other[i]; physical = curr.physical() >> effective_block_size_log2; if (physical == last) { /* nothing to do */ } else if (physical > last) { /* add "hole" with logical == physical */ append0(last, last, physical - last, FC_DEFAULT_USER_DATA); } else { /* oops.. some programmer really screwed up */ const fr_extent & prev = other[i-1]; ff_log(FC_FATAL, 0, "internal error in ft_map::complement0_physical_shift():"); ff_log(FC_FATAL, 0, "\textent[%" FT_ULL "] = {physical = %" FT_ULL ", logical = %" FT_ULL ", length = %" FT_ULL " /* physical end = %" FT_ULL " */} does not end before", (ft_ull) (i-1), (ft_ull) prev.physical(), (ft_ull) prev.logical(), (ft_ull) prev.length(), (ft_ull) (prev.physical() + prev.length())); ff_log(FC_FATAL, 0, "\textent[%" FT_ULL "] = {physical = %" FT_ULL ", logical = %" FT_ULL ", length = %" FT_ULL " /* physical end = %" FT_ULL " */}", (ft_ull) i, (ft_ull) curr.physical(), (ft_ull) curr.logical(), (ft_ull) curr.length(), (ft_ull) (curr.physical() + curr.length())); ff_assert_fail("internal error in ft_map::complement0_physical_shift(): map is not sorted by ->physical()"); } last = physical + (curr.length() >> effective_block_size_log2); } device_length >>= effective_block_size_log2; if (last < device_length) { /* add last "hole" with logical == physical */ append0(last, last, device_length - last, FC_DEFAULT_USER_DATA); } } /** * makes the logical complement of 'other' vector, * i.e. calculates the logical extents NOT used in 'other' vector, * shifts them by effective_block_size_log2, * and inserts it in this map (with user_data = FC_DEFAULT_USER_DATA). * * since the file(s) contained in such complementary extents are not known, * all calculated extents will have ->logical == ->physical. * * 'other' must be already sorted by logical! * does not merge and does not check for merges * does not check for overflows */ template void fr_map::complement0_logical_shift(const fr_vector & other, ft_uoff effective_block_size_log2, ft_uoff device_length) { T logical, last; ft_size i, n = other.size(); if (empty()) last = 0; else { const mapped_type & back = (--this->end())->second; last = back.logical + back.length; } /* loop on 'other' extents */ for (i = 0; i < n; i++) { const fr_extent & curr = other[i]; logical = curr.logical() >> effective_block_size_log2; if (logical == last) { /* nothing to do */ } else if (logical > last) { /* add "hole" with logical == logical */ append0(last, last, logical - last, FC_DEFAULT_USER_DATA); } else { /* oops.. some programmer really screwed up */ const fr_extent & prev = other[i-1]; ff_log(FC_FATAL, 0, "internal error in ft_map::complement0_logical_shift():"); ff_log(FC_FATAL, 0, "\textent[%" FT_ULL "] = {physical = %" FT_ULL ", logical = %" FT_ULL ", length = %" FT_ULL " /* logical end = %" FT_ULL " */} does not end before", (ft_ull) (i-1), (ft_ull) prev.physical(), (ft_ull) prev.logical(), (ft_ull) prev.length(), (ft_ull) (prev.logical() + prev.length())); ff_log(FC_FATAL, 0, "\textent[%" FT_ULL "] = {physical = %" FT_ULL ", logical = %" FT_ULL ", length = %" FT_ULL " /* logical end = %" FT_ULL " */}", (ft_ull) i, (ft_ull) curr.physical(), (ft_ull) curr.logical(), (ft_ull) curr.length(), (ft_ull) (curr.logical() + curr.length())); ff_assert_fail("somebody programmed a call to ft_map::complement0_logical_shift() with an argument not sorted by ->logical() !"); } last = logical + (curr.length() >> effective_block_size_log2); } /* * NOTE: right-shifting device_length by effective_block_size_log2 * forgets any odd-sized last device block */ device_length >>= effective_block_size_log2; if (last < device_length) { /* add last "hole" with logical == logical */ append0(last, last, device_length - last, FC_DEFAULT_USER_DATA); } } /** print map contents to log */ template void fr_map::show(const char * label1, const char * label2, ft_uoff effective_block_size, ft_log_level level) const { fr_extent::show(this->begin(), this->end(), this->size(), label1, label2, effective_block_size, level); } FT_NAMESPACE_END fstransform-0.9.4/fsremap/src/map_stat.cc000066400000000000000000000022201345021500300204200ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * map_stat.cc * * Created on: Feb 27, 2011 * Author: max */ #include "first.hh" // for FT_*TEMPLATE* macros */ #ifdef FT_HAVE_EXTERN_TEMPLATE # include "map_stat.t.hh" FT_TEMPLATE_INSTANTIATE(FT_TEMPLATE_map_stat_hh) #endif /* FT_HAVE_EXTERN_TEMPLATE */ fstransform-0.9.4/fsremap/src/map_stat.hh000066400000000000000000000077301345021500300204450ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * map_stat.hh * * Created on: Mar 12, 2011 * Author: max */ #ifndef FSREMAP_MAP_STAT_HH #define FSREMAP_MAP_STAT_HH #include "map.hh" // for fr_map FT_NAMESPACE_BEGIN template class fr_map_stat : public fr_map { private: typedef fr_map super_type; typedef typename fr_map::iterator iterator; T this_total_count; /**< total length (number of blocks) in this map extents */ T this_used_count; /**< used length (number of blocks) in this map extents */ public: // construct empty fr_map_stat fr_map_stat(); // destructor ~fr_map_stat(); // duplicate a fr_map_stat, i.e. initialize this fr_map as a copy of other. fr_map_stat(const fr_map & other); // duplicate a fr_map_stat, i.e. initialize this fr_map as a copy of other. fr_map_stat(const fr_map_stat & other); // copy fr_map_stat, i.e. set fr_map_stat fr_map contents as a copy of other's contents. const fr_map_stat & operator=(const fr_map & other); // copy fr_map_stat, i.e. set fr_map_stat fr_map contents as a copy of other's contents. const fr_map_stat & operator=(const fr_map_stat & other); /** clear this fr_map_stat. also sets total_count, used_count and free_count to zero */ void clear(); /** same as super_type::insert(T,T,T,ft_size), but also updates used_count() */ FT_INLINE iterator stat_insert(T physical, T logical, T length, ft_size user_data) { this_used_count += length; return super_type::insert(physical, logical, length, user_data); } /** same as super_type::remove(iterator), but also updates used_count() */ FT_INLINE void stat_remove(iterator iter) { super_type::remove(iter); this_used_count -= iter->second.length; } /** same as super_type::remove(T, T, T), but also updates used_count() */ FT_INLINE void stat_remove(T physical, T logical, T length) { super_type::remove(physical, logical, length); this_used_count -= length; } /** * remove an initial part of an existing extent from this fr_map. * returns iterator to new, smaller extent, or end() if the whole extent was removed */ FT_INLINE void stat_remove_front(iterator iter, T shrink_length) { super_type::remove_front(iter, shrink_length); this_used_count -= shrink_length; } FT_INLINE T total_count() const { return this_total_count; } FT_INLINE T used_count() const { return this_used_count; } FT_INLINE T free_count() const { return this_total_count - this_used_count; } FT_INLINE void total_count(T n) { this_total_count = n; } FT_INLINE void used_count(T n) { this_used_count = n; } FT_INLINE void used_count_add(T n) { this_used_count += n; } FT_INLINE void used_count_sub(T n) { this_used_count -= n; } }; FT_NAMESPACE_END #ifdef FT_HAVE_EXTERN_TEMPLATE # define FT_TEMPLATE_map_stat_hh(ft_prefix, T) ft_prefix class FT_NS fr_map_stat< T >; FT_TEMPLATE_DECLARE(FT_TEMPLATE_map_stat_hh) #else # include "map_stat.t.hh" #endif /* FT_HAVE_EXTERN_TEMPLATE */ #endif /* FSREMAP_MAP_STAT_HH */ fstransform-0.9.4/fsremap/src/map_stat.t.hh000066400000000000000000000051121345021500300206770ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * map_stat.t.hh * * Created on: Mar 12, 2011 * Author: max */ #include "first.hh" #include "map_stat.hh" // for fr_map_stat FT_NAMESPACE_BEGIN // construct empty fr_map_stat template fr_map_stat::fr_map_stat() : super_type(), this_total_count(0), this_used_count(0) { } // destroy fr_map_stat template fr_map_stat::~fr_map_stat() { } // duplicate a fr_map_stat, i.e. initialize this fr_map_stat as a copy of other. template fr_map_stat::fr_map_stat(const fr_map & other) : super_type(other), this_total_count(0), this_used_count(0) { } // duplicate a fr_map_stat, i.e. initialize this fr_map_stat as a copy of other. template fr_map_stat::fr_map_stat(const fr_map_stat & other) : super_type(other), this_total_count(other.this_total_count), this_used_count(other.this_used_count) { } // copy fr_map_stat, i.e. set this fr_map_stat contents as a copy of other's contents. template const fr_map_stat & fr_map_stat::operator=(const fr_map & other) { super_type::operator=(other); this_total_count = this_used_count = 0; return * this; } // copy fr_map_stat, i.e. set this fr_map_stat contents as a copy of other's contents. template const fr_map_stat & fr_map_stat::operator=(const fr_map_stat & other) { super_type::operator=(other); this_total_count = other.this_total_count; this_used_count = other.this_used_count; return * this; } /** clear this fr_map_stat. also sets total_count, used_count and free_count to zero */ template void fr_map_stat::clear() { super_type::clear(); this_total_count = this_used_count = 0; } FT_NAMESPACE_END fstransform-0.9.4/fsremap/src/misc.cc000066400000000000000000000234301345021500300175510ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * misc.cc * * Created on: Mar 9, 2011 * Author: max */ #include "first.hh" #if defined(FT_HAVE_STDLIB_H) # include // for srandom(), random(), rand(), srand() #elif defined(FT_HAVE_CSTDLIB) # include // for srandom(), random(), rand(), srand() #endif #if defined(FT_HAVE_TIME_H) # include // for time() #elif defined(FT_HAVE_CTIME) # include // for time() #endif #ifdef FT_HAVE_SYS_TIME_H # include // for struct timeval, gettimeofday() #endif #include "misc.hh" // declarations of the functions defined here FT_NAMESPACE_BEGIN static const ft_ull max_n_div_10 = (ft_ull)-1 / 10; const char max_n_rem_10 = (char)((ft_ull)-1 % 10); static int ff_str2ull_(const char *& str, ft_ull * ret_n) { ft_ull n = 0; char ch; while ((ch = *str) >= '0' && ch <= '9') { str++; ch -= '0'; if (n < max_n_div_10 || (n == max_n_div_10 && ch <= max_n_rem_10)) { n *= 10; n += ch; } else return EOVERFLOW; } * ret_n = n; return 0; } int ff_str2ull(const char * str, ft_ull * ret_n) { ft_ull n = 0; int err = ff_str2ull_(str, & n); if (err == 0 && *str != '\0') return EINVAL; if (err == 0) * ret_n = n; return err; } /** convert string with optional [k|M|G|T|P|E|Z|Y] scale to unsigned number */ int ff_str2ull_scaled(const char * str, ft_ull * ret_n) { ft_ull scale, n = 0; int err; do { if ((err = ff_str2ull_(str, & n)) != 0) break; switch (*str) { case '\0': scale = 0; * ret_n = n; return err; case 'k': scale = 10; break; case 'M': scale = 20; break; case 'G': scale = 30; break; case 'T': scale = 40; break; case 'P': scale = 50; break; case 'E': scale = 60; break; case 'Z': scale = 70; break; case 'Y': scale = 80; break; default: err = EINVAL; break; } if (err != 0) break; /* overflow? */ if (scale >= 8*sizeof(ft_ull) || n > (ft_ull)-1 >> scale) { err = EOVERFLOW; break; } n <<= scale; * ret_n = n; } while (0); return err; } int ff_now(double & ret_time) { int err; #ifdef FT_HAVE_GETTIMEOFDAY struct timeval tv; if ((err = gettimeofday(& tv, NULL)) == 0) { ret_time = (double) tv.tv_sec + (double) tv.tv_usec * 1e-6; return err; } /* error in gettimeofday(), fall back on time() */ #else # warning gettimeofday() not found on this platform. timestamps and "time left" estimations will be less accurate #endif errno = err = 0; time_t now = time(NULL); if (now == (time_t)-1) err = -errno; if (err == 0) ret_time = (double) now; return err; } #if defined(FT_HAVE_SRANDOM) && defined(FT_HAVE_RANDOM) # define ff_misc_random_init(seed) srandom(seed) # define ff_misc_random() random() # define FF_RAND_MAX RAND_MAX #else # define ff_misc_random_init(seed) srand(seed) # define ff_misc_random() rand() # define FF_RAND_MAX RAND_MAX #endif /** return a random number in the range [0,n] */ ft_ull ff_random(ft_ull n) { static bool initialized = false; if (!initialized) { initialized = true; ff_misc_random_init(time(NULL)); } ft_ull r; if (n == 0) return 0; if (n < FF_RAND_MAX) { ft_ull max = FF_RAND_MAX - (FF_RAND_MAX % (n + 1)); do { r = ff_misc_random(); } while (r > max); return r / (max / (n + 1)); } if (n == FF_RAND_MAX) return ff_misc_random(); const ft_ull max_p_1 = (ft_ull)FF_RAND_MAX + 1; const ft_ull n_hi = (n + FF_RAND_MAX) / max_p_1; do { r = ff_random(n_hi) * max_p_1 + ff_misc_random(); } while (r > n); return r; } static char const* fc_pretty_size_unit[] = { "", "kilo", "mega", "giga", "tera", "peta", "exa", "zeta", "yotta", }; enum { fc_pretty_size_len = sizeof(fc_pretty_size_unit)/sizeof(fc_pretty_size_unit[0]) }; /** * return human-readable representation of len, * with [kilo|mega|giga|tera|peta|exa|zeta|yotta] scale as appropriate */ const char * ff_pretty_size(ft_uoff len, double * ret_pretty_len) { double pretty_len = (double) len; ft_size i; for (i = 0; i < fc_pretty_size_len-1 && pretty_len >= 1024.0; i++) pretty_len *= .0009765625; // exactly 1/1024 * ret_pretty_len = pretty_len; return fc_pretty_size_unit[i]; } static char const* fc_pretty_time_unit[] = { "second", "minute", "hour", "day", "month", "year", }; static const double fc_pretty_time[] = { 1.0, 60.0, 3600.0, 86400.0, 86400.0 * 30, 86400.0 * 365, }; enum { fc_pretty_time_len = sizeof(fc_pretty_time)/sizeof(fc_pretty_time[0]) }; /** * return human-readable representation of time, * with [second|minute|hour|day|month|year] scale as appropriate */ char const * ff_pretty_time(double time, double * ret_pretty_time) { ft_size i = 0; for (; i < fc_pretty_time_len - 1; i++) { if (time < fc_pretty_time[i+1]) break; } * ret_pretty_time = time / fc_pretty_time[i]; return fc_pretty_time_unit[i]; } /** * return human-readable representation of time, * with [second|minute|hour|day|month|year] scale as appropriate */ void ff_pretty_time2(double time, ft_ull * ret_pretty_time1, char const ** ret_pretty_label1, ft_ull * ret_pretty_time2, char const ** ret_pretty_label2) { ft_size i = 0; for (; i < fc_pretty_time_len - 1; i++) { if (time < fc_pretty_time[i+1]) break; } double time1 = time / fc_pretty_time[i]; * ret_pretty_time1 = ff_pretty_number(time1); * ret_pretty_label1 = fc_pretty_time_unit[i]; if (ret_pretty_time2 == NULL || ret_pretty_label2 == NULL) return; * ret_pretty_time2 = 0; * ret_pretty_label2 = NULL; if (i == 0 || time1 <= 1.0 || time1 > 1.9) return; time -= (ft_ull) time1 * fc_pretty_time[i]; if (time <= 0.0) return; ft_size j = 0; for (j = 0; j < fc_pretty_time_len - 1; j++) { if (time < fc_pretty_time[j+1]) break; } if (j + 1 == i) { * ret_pretty_time1 = 1; * ret_pretty_time2 = ff_pretty_number(time / fc_pretty_time[j]); * ret_pretty_label2 = fc_pretty_time_unit[j]; } } /** * return approximate number, rounding to "one-and-a-half" significant digits. * if t <= 10, return (ft_ull)(t + 0.5) * if t <= 30, return ((ft_ull)(t/5 + 0.5)) * 5 * if t <= 100, return ((ft_ull)(t/10 + 0.5)) * 10 * if t <= 300, return ((ft_ull)(t/50 + 0.5)) * 50 * otherwise return ((ft_ull)(t/100 + 0.5)) * 100 */ ft_ull ff_pretty_number(double t) { ft_ull n; if (t <= 10.0) n = (ft_ull)(t + 0.5); else if (t <= 30.0) n = 5 * (ft_ull)(t*0.2 + 0.5); else if (t <= 100.0) n = 10 * (ft_ull)(t*0.1 + 0.5); else if (t <= 300.0) n = 50 * (ft_ull)(t*0.02 + 0.5); else n = 100 * (ft_ull)(t*0.01 + 0.5); return n; } /** * Show progress. logs a message like * {prefix}progress: {percentage}% done, {bytes_left} bytes{suffix}, estimated {time_left} left" * * if time_left < 0, omits the part "estimated {time_left} left" */ void ff_show_progressl(const char * caller_file, int caller_file_len, const char * caller_func, int caller_line, ft_log_level log_level, const char * prefix, double percentage, ft_uoff bytes_left, const char * suffix, double time_left) { double pretty_len = 0.0; const char * pretty_label = ff_pretty_size(bytes_left, & pretty_len); if (time_left < 0) { ff_log(log_level, 0, "%sprogress: %4.1f%% done, %5.1f %sbytes%s", prefix, percentage, pretty_len, pretty_label, suffix); return; } ft_ull time_left1 = 0, time_left2 = 0; const char * time_left_label1 = NULL, * time_left_label2 = NULL; ff_pretty_time2(time_left, & time_left1, & time_left_label1, & time_left2, & time_left_label2); /* we write something like "1 hour and 20 minutes" instead of just "1 hour" or "1.3 hours" */ if (time_left_label2 != NULL) { ff_logl(caller_file, caller_file_len, caller_func, caller_line, log_level, 0, "%sprogress: %4.1f%% done, %5.1f %sbytes%s, estimated %2" FT_ULL " %s%s and %2" FT_ULL " %s%s left", prefix, percentage, pretty_len, pretty_label, suffix, time_left1, time_left_label1, (time_left1 != 1 ? "s": ""), time_left2, time_left_label2, (time_left2 != 1 ? "s": "")); } else { ff_logl(caller_file, caller_file_len, caller_func, caller_line, log_level, 0, "%sprogress: %4.1f%% done, %5.1f %sbytes%s, estimated %2" FT_ULL " %s%s left", prefix, percentage, pretty_len, pretty_label, suffix, time_left1, time_left_label1, (time_left1 != 1 ? "s": "")); } } FT_NAMESPACE_END fstransform-0.9.4/fsremap/src/misc.hh000066400000000000000000000121571345021500300175670ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * misc.hh * * Created on: Mar 9, 2011 * Author: max */ #ifndef FSTRANSFORM_MISC_HH #define FSTRANSFORM_MISC_HH #if defined(FT_HAVE_ERRNO_H) # include // for EINVAL, EOVERFLOW #elif defined(FT_HAVE_CERRNO) && defined(__cplusplus) # include // for EINVAL, EOVERFLOW #endif #include "types.hh" // for ft_size, ft_uoff #include "log.hh" // for ft_log_level FT_NAMESPACE_BEGIN template FT_INLINE T ff_min2(T a, T b) { return a < b ? a : b; } template FT_INLINE T ff_min3(T a, T b, T c) { return ff_min2(ff_min2(a, b), c); } template FT_INLINE T ff_max2(T a, T b) { return a > b ? a : b; } template FT_INLINE T ff_max3(T a, T b, T c) { return ff_max2(ff_max2(a, b), c); } /** * is it possible to sum a and b (a+b), or it will overflow? * note: T must be unsigned! */ template FT_INLINE bool ff_can_sum(T a, T b) { return a <= ~b; } /** convert string to unsigned number */ int ff_str2ull(const char * str, ft_ull * ret_n); /** convert string with optional [k|M|G|T|P|E|Z|Y] scale to unsigned number */ int ff_str2ull_scaled(const char * str, ft_ull * ret_n); /** * convert an integer 'n' from type T1 to type T2, * or return EOVERFLOW if it overflows. */ template int ff_narrow(T1 n, T2 * ret_n) { T2 n2 = (T2) n; if ((n < 0) != (n2 < 0) || n != (T1) n2) return EOVERFLOW; * ret_n = n2; return 0; } /** convert string to unsigned number */ template int ff_str2un(const char * str, T * ret_n) { ft_ull ln; int err = ff_str2ull(str, & ln); if (err == 0) err = ff_narrow(ln, ret_n); return err; } /** convert string with optional [k|M|G|T|P|E|Z|Y] scale to unsigned number */ template int ff_str2un_scaled(const char * str, T * ret_n) { ft_ull ln; int err = ff_str2ull_scaled(str, & ln); if (err == 0) err = ff_narrow(ln, ret_n); return err; } void ff_init_random(ft_ull seed); /** return a random number in the range [0,max] */ ft_ull ff_random(ft_ull max); /** return p != NULL ? p : default_p */ template FT_INLINE T * ff_if_null(T * p, T * default_p) { return p != NULL ? p : default_p; } int ff_now(double & ret_time); /** * return human-readable representation of length, * with [kilo|mega|giga|tera|peta|exa|zeta|yotta] scale as appropriate */ const char * ff_pretty_size(ft_uoff length, double * ret_pretty_len); /** * return human-readable representation of time, * with [second|minute|hour|day|month|year] scale as appropriate */ const char * ff_pretty_time(double time, double * ret_pretty_time); /** * return human-readable representation of time, * with [second|minute|hour|day|month|year] scale as appropriate */ void ff_pretty_time2(double time, ft_ull * ret_pretty_time1, char const ** ret_pretty_label1, ft_ull * ret_pretty_time2 = NULL, char const ** ret_pretty_label2 = NULL); /** * return approximate number, rounding to "one-and-a-half" significant digits. * if t <= 10, return (ft_ull)(t + 0.5) * if t <= 30, return ((ft_ull)(t*5 + 0.5)) / 5 * if t <= 100, return ((ft_ull)(t*10 + 0.5)) / 10 * if t <= 300, return ((ft_ull)(t*50 + 0.5)) / 50 * otherwise return ((ft_ull)(t*100 + 0.5)) / 100 */ ft_ull ff_pretty_number(double t); /** * Show progress. logs a message like * {prefix}progress: {percentage}% done, {bytes_left} bytes{suffix}, estimated {time_left} left" * * if time_left < 0, omits the part "estimated {time_left} left" */ #define ff_show_progress(log_level, prefix, percentage, bytes_left, suffix, ...) ff_show_progressl( \ FT_THIS_FILE, sizeof(FT_THIS_FILE), FT_THIS_FUNCTION, FT_THIS_LINE, \ log_level, prefix, percentage, bytes_left, suffix, __VA_ARGS__) /** * Show progress. logs a message like * {prefix}progress: {percentage}% done, {bytes_left} bytes{suffix}, estimated {time_left} left" * * if time_left < 0, omits the part "estimated {time_left} left" */ void ff_show_progressl(const char * caller_file, int caller_file_len, const char * caller_func, int caller_line, ft_log_level log_level, const char * prefix, double percentage, ft_uoff bytes_left, const char * suffix, double time_left = -1.0); FT_NAMESPACE_END #endif /* FSTRANSFORM_MISC_HH */ fstransform-0.9.4/fsremap/src/mstring.cc000066400000000000000000000056011345021500300203010ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * mstring.hh * * Created on: Apr 25, 2012 * Author: max */ #include "first.hh" #include "misc.hh" // for ft_min2() #include "mstring.hh" // for ft_mstring #if defined(FT_HAVE_STRING_H) # include // for memcmp(), memcpy(), memrchr() #elif defined(FT_HAVE_CSTRING) # include // for memcmp(), memcpy(), memrchr() #endif FT_NAMESPACE_BEGIN /** default constructor. */ ft_mstring::ft_mstring() : txt(NULL), len(0) { } /** copy constructor. */ ft_mstring::ft_mstring(const ft_mstring & other) : txt(other.txt), len(other.len) { } /** constructor. shares the char array inside 'other', does not copy it */ ft_mstring::ft_mstring(const ft_mstring & other, ft_size offset, ft_size length) : txt(other.txt + ff_min2(offset, other.len)), len(other.len <= offset ? 0 : ff_min2(length, other.len - offset)) { } /** constructor. shares the char array 'str', does not copy it */ ft_mstring::ft_mstring(const char * str, ft_size str_len) : txt(str), len(str_len) { } /** assignment operator */ const ft_mstring & ft_mstring::operator=(const ft_mstring & other) { // ok also if this == & other txt = other.txt; len = other.len; return * this; } // comparison operator bool ft_mstring::operator==(const ft_mstring & other) const { if (len != other.len) return false; if (txt == other.txt) // also catches this == & other return true; return memcmp(txt, other.txt, len) == 0; } // comparison operator bool ft_mstring::operator<(const ft_mstring & other) const { if (len != 0 && other.len != 0 && txt != other.txt) { int cmp = memcmp(txt, other.txt, ff_min2(len, other.len)); if (cmp != 0) // different contents return cmp < 0; } // at least one empty string, or same contents in the common prefix. // also catches this == & other return len < other.len; } ft_size ft_mstring::rfind(char ch) const { if (len != 0) { const char * match = (const char *) memrchr(txt, (unsigned char) ch, len); if (match != NULL) return match - txt; } return npos; } FT_NAMESPACE_END fstransform-0.9.4/fsremap/src/mstring.hh000066400000000000000000000052061345021500300203140ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * mstring.hh * * Created on: Apr 25, 2012 * Author: max */ #ifndef FSTRANSFORM_MSTRING_HH #define FSTRANSFORM_MSTRING_HH #include "types.hh" // for ft_size FT_NAMESPACE_BEGIN /** * immutable string. initialized with a const char *, * keeps a reference to the char array instead of copying its contents */ class ft_mstring { private: const char * txt; ft_size len; public: enum { npos = (ft_size)-1 }; /** default constructor. */ ft_mstring(); /** copy constructor. */ ft_mstring(const ft_mstring & other); /** constructor. shares the char array inside 'other', does not copy it */ ft_mstring(const ft_mstring & other, ft_size offset, ft_size length); /** constructor. shares the char array 'str', does not copy it */ ft_mstring(const char * str, ft_size str_len); /** constructor. shares the char array 'str', does not copy it */ template ft_mstring(const char (& str)[N]) : txt(str), len(N-1) { } /** assignment operator */ const ft_mstring & operator=(const ft_mstring & other); /** destructor. */ FT_INLINE ~ft_mstring() { } FT_INLINE const char & operator[](ft_size i) const { return txt[i]; } FT_INLINE ft_size size() const { return len; } // comparison operators bool operator==(const ft_mstring & other) const; FT_INLINE bool operator!=(const ft_mstring & other) const { return !(*this == other); } // comparison operators bool operator<(const ft_mstring & other) const; FT_INLINE bool operator<=(const ft_mstring & other) const { return !(other < *this); } FT_INLINE bool operator> (const ft_mstring & other) const { return other < *this; } FT_INLINE bool operator>=(const ft_mstring & other) const { return !(*this < other); } ft_size rfind(char ch) const; }; FT_NAMESPACE_END #endif /* FSTRANSFORM_MSTRING_HH */ fstransform-0.9.4/fsremap/src/pool.cc000066400000000000000000000022651345021500300175720ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * pool.cc * * Created on: Mar 8, 2011 * Author: max */ #include "first.hh" // for FT_*TEMPLATE* macros */ #include "types.hh" // for ft_uint, ft_uoff #ifdef FT_HAVE_EXTERN_TEMPLATE # include "pool.t.hh" FT_TEMPLATE_INSTANTIATE(FT_TEMPLATE_pool_hh) #endif /* FT_HAVE_EXTERN_TEMPLATE */ fstransform-0.9.4/fsremap/src/pool.hh000066400000000000000000000102511345021500300175760ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * pool.hh * * Created on: Mar 8, 2011 * Author: max */ #ifndef FSREMAP_POOL_HH #define FSREMAP_POOL_HH #include "check.hh" #include // for std::map #include // for std::vector #include "map.hh" // for fr_map FT_NAMESPACE_BEGIN template class fr_pool_entry : public std::vector::iterator> { }; /** * pool of extents, ordered by ->length. the pool is backed by a fr_map, * so that modifications to the pool are propagated to the backing fr_map * * used for best-fit allocation of free space, when free space is represented * by a fr_map of extents. */ template class fr_pool : private std::map > { private: typedef std::map > super_type; typedef typename fr_map::iterator map_iterator; typedef typename fr_map::key_type map_key_type; typedef typename fr_map::mapped_type map_mapped_type; typedef typename fr_map::value_type map_value_type; public: typedef typename super_type::key_type key_type; typedef typename super_type::mapped_type mapped_type; typedef typename super_type::value_type value_type; typedef typename super_type::iterator iterator; typedef typename super_type::const_iterator const_iterator; private: fr_map & backing_map; /** initialize this pool to reflect contents of backing fr_map */ void init(); /** insert into this pool an extent _ALREADY_ present in backing map */ void insert0(map_iterator map_iter); /** * "allocate" from the single extent 'iter' in this pool and shrink it * to store the single extent 'map_iter'. * remove allocated (and renumbered) extent from map and write it into map_allocated */ void allocate_unfragmented(map_iterator map_iter, fr_map & map, fr_map & map_allocated, iterator iter); /** * "allocate" a single fragment from this pool to store the single extent 'map_iter'. * shrink extent from map (leaving unallocated portion) and write the allocated portion into map_allocated. * * return iterator to remainder of extent that still needs to be allocated */ map_iterator allocate_fragment(map_iterator map_iter, fr_map & map, fr_map & map_allocated); public: fr_pool(fr_map & map); /* * "allocate" (and remove) extents from this pool to store 'map' extents using a best-fit strategy. * remove allocated (and renumbered) extents from 'map' and write them into 'map_allocated', * fragmenting them if needed */ void allocate_all(fr_map & map, fr_map & map_allocated); /** * "allocate" using a best-fit strategy (and remove) extents from this pool * to store the single extent 'map_iter', which must belong to 'map'. * remove allocated (and renumbered) extent from map and write it into map_allocated, * fragmenting it if needed. */ void allocate(map_iterator map_iter, fr_map & map, fr_map & map_allocated); }; FT_NAMESPACE_END #ifdef FT_HAVE_EXTERN_TEMPLATE # define FT_TEMPLATE_pool_hh(ft_prefix, T) ft_prefix class FT_NS fr_pool< T >; FT_TEMPLATE_DECLARE(FT_TEMPLATE_pool_hh) #else # include "pool.t.hh" #endif /* FT_HAVE_EXTERN_TEMPLATE */ #endif /* FSREMAP_POOL_HH */ fstransform-0.9.4/fsremap/src/pool.t.hh000066400000000000000000000144031345021500300200430ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * pool.hh * * Created on: Mar 8, 2011 * Author: max */ #include "first.hh" #include "assert.hh" // for ff_assert macro #include "pool.hh" // for fr_pool FT_NAMESPACE_BEGIN template fr_pool::fr_pool(fr_map & map) : backing_map(map) { init(); } /** initialize this pool to reflect contents of backing fr_map */ template void fr_pool::init() { map_iterator begin = backing_map.begin(), iter = backing_map.end(); /* * iterate backward to have lower physicals in the last std::vector positions, * so that they will be used first */ while (begin != iter) insert0(--iter); } /** insert into this pool an extent _ALREADY_ present in backing map */ template void fr_pool::insert0(map_iterator map_iter) { (*this)[map_iter->second.length].push_back(map_iter); } /** * "allocate" from the single extent 'iter' in this pool and shrink it * to store the single extent 'map_iter'. * remove allocated (and renumbered) extent from map and write it into map_allocated */ template void fr_pool::allocate_unfragmented(map_iterator map_iter, fr_map & map, fr_map & map_allocated, iterator iter) { map_value_type & map_value = * map_iter; T physical = map_value.first.physical; T length = map_value.second.length; ft_size user_data = map_value.second.user_data; /* check that 'iter' extent is big enough to fit map_iter */ fr_pool_entry & pool_entry = iter->second; map_iterator pool_iter = pool_entry.back(); map_mapped_type & pool_value = pool_iter->second; T pool_value_logical = pool_value.logical; T pool_value_length = iter->first; ff_assert(pool_value_length == pool_value.length); ff_assert(pool_value_length >= length); /* update maps to reflect allocation */ map_allocated.insert(physical, pool_value_logical, length, user_data); map.remove(map_iter); /* remove extent from pool_entry */ pool_entry.pop_back(); /* if pool_entry is empty, remove it from this pool */ if (pool_entry.empty()) super_type::erase(iter); /* shrink 'iter' extent inside backing map */ pool_iter = backing_map.remove_front(pool_iter, length); if (pool_iter != backing_map.end()) /* we have a remainder: reinsert it into this pool */ insert0(pool_iter); } /** * "allocate" a single fragment from this pool to store the single extent 'map_iter'. * shrink extent from map (leaving unallocated portion) and write the allocated portion into map_allocated. * * return iterator to remainder of extent that still needs to be allocated */ template typename fr_pool::map_iterator fr_pool::allocate_fragment(map_iterator map_iter, fr_map & map, fr_map & map_allocated) { map_value_type & map_value = * map_iter; T physical = map_value.first.physical; T length = map_value.second.length; ft_size user_data = map_value.second.user_data; ff_assert(!this->empty()); iterator iter = this->end(); // use the largest extent we have --iter; T pool_value_length = iter->first; fr_pool_entry & pool_entry = iter->second; map_iterator pool_iter = pool_entry.back(); map_mapped_type & pool_value = pool_iter->second; T pool_value_logical = pool_value.logical; ff_assert(pool_value_length == pool_value.length); ff_assert(pool_value_length < length); /* update maps to reflect partial allocation */ map_allocated.insert(physical, pool_value_logical, pool_value_length, user_data); map_iter = map.remove_front(map_iter, pool_value_length); /* remove extent from pool_entry */ pool_entry.pop_back(); /* if pool_entry is empty, remove it from this pool */ if (pool_entry.empty()) super_type::erase(iter); /* remove 'iter' extent from backing map */ backing_map.remove(pool_iter); /* return iterator to remainder of extent that still needs to be allocated */ return map_iter; } /* * "allocate" (and remove) extents from this pool to store map extents using a best-fit strategy. * remove allocated (and renumbered) extents from map and write them into map_allocated, * fragmenting them if needed */ template void fr_pool::allocate_all(fr_map & map, fr_map & map_allocated) { map_iterator map_iter = map.begin(), map_iter_tmp, map_end = map.end(); while (map_iter != map_end && !this->empty()) { map_iter_tmp = map_iter; ++map_iter; allocate(map_iter_tmp, map, map_allocated); } } /** * "allocate" using a best-fit strategy (and remove) extents from this pool * to store the single extent 'map_iter', which must belong to 'map'. * remove allocated (and renumbered) extent from map and write it into map_allocated, * fragmenting it if needed. */ template void fr_pool::allocate(map_iterator map_iter, fr_map & map, fr_map & map_allocated) { iterator iter, end = this->end(); T length; while ((length = map_iter->second.length) != 0 && !this->empty()) { if ((iter = this->lower_bound(length)) != end) { /* found a pool entry big enough to fit extent remainder */ allocate_unfragmented(map_iter, map, map_allocated, iter); return; } /* no pool entry is big enough: we need to fragment the extent */ map_iter = allocate_fragment(map_iter, map, map_allocated); } } FT_NAMESPACE_END fstransform-0.9.4/fsremap/src/remap.cc000066400000000000000000000740071345021500300177300ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2017 Massimiliano Ghilardi * * 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 . * * remap.cc * * Created on: Feb 14, 2011 * Author: max */ #include "first.hh" #if defined(FT_HAVE_STRING_H) # include // for strcmp() #elif defined(FT_HAVE_CSTRING) # include // for strcmp() #endif #if defined(FT_HAVE_STRING_H) # include // for atoi() #elif defined(FT_HAVE_CSTRING) # include // for atoi() #endif #include "log.hh" // for ff_log() #include "map.hh" // for fr_map #include "vector.hh" // for fr_vector #include "dispatch.hh" // for fr_dispatch #include "remap.hh" // for fr_remap #include "misc.hh" // for ff_strtoul() #include "io/io.hh" // for fr_io #include "io/io_posix.hh" // for fr_io_posix #ifdef FT_HAVE_IO_PREALLOC # include "io/io_prealloc.hh" // for fr_io_prealloc #endif #include "io/io_self_test.hh" // for fr_io_self_test #include "io/util_dir.hh" // for ff_mkdir() FT_NAMESPACE_BEGIN enum { FC_DEVICE = FT_IO_NS fr_io_posix::FC_DEVICE, FC_LOOP_FILE = FT_IO_NS fr_io_posix::FC_LOOP_FILE, FC_FILE_COUNT = FT_IO_NS fr_io_posix::FC_FILE_COUNT }; static char const* const* label = FT_IO_NS fr_io::label; static char const* const* LABEL = FT_IO_NS fr_io::LABEL; /** constructor */ fr_remap::fr_remap() : this_job(NULL), this_persist(NULL), this_io(NULL), this_ui(NULL), quit_immediately(false) { } /** destructor. calls quit_io(), quit_ui() and quit_job_persist() */ fr_remap::~fr_remap() { quit_io(); quit_ui(); quit_job_persist(); } /** * high-level main method. * calls in sequence: init(argc, argv), run() and quit_io() * * expects argc == 4 and four arguments in argv: * program_name, DEVICE, LOOP-FILE and ZERO-FILE. * * return 0 if success, else error. * if invoked with the argument "--help" or "--version", calls usage() or version() and immediately returns 0 */ int fr_remap::main(int argc, char const* const* argv) { fr_remap remapper; int err = remapper.init(argc, argv); if (err == 0 && !remapper.quit_immediately) err = remapper.run(); /* * note 1.2.2) fsremap::main() must check for unreported errors * and log them them with message "failed with unreported error" */ if (!ff_log_is_reported(err)) err = ff_log(FC_ERROR, err, "failed with unreported error"); return err; } /** print command-line usage to stdout and return 0 */ int fr_remap::usage(const char * program_name) { quit_immediately = true; ff_log(FC_NOTICE, 0, "Usage: %s [OPTION]... %s %s [%s]", program_name, LABEL[0], LABEL[1], LABEL[2]); ff_log(FC_NOTICE, 0, " or: %s [OPTION]... --resume-job=JOB_ID %s", program_name, LABEL[FC_DEVICE]); ff_log(FC_NOTICE, 0, "Replace the contents of %s with the contents of %s, i.e. write %s onto %s", LABEL[FC_DEVICE], LABEL[FC_LOOP_FILE], LABEL[FC_LOOP_FILE], LABEL[FC_DEVICE]); ff_log(FC_NOTICE, 0, "even if %s is inside a file system _inside_ %s\n", LABEL[FC_LOOP_FILE], LABEL[FC_DEVICE]); return ff_log (FC_NOTICE, 0, "Mandatory arguments to long options are mandatory for short options too.\n" " -- end of options. treat subsequent parameters as arguments\n" " even if they start with '-'\n" " -a, --no-questions automatic run: do not ask any question\n" " --clear=all clear all free blocks after remapping (default)\n" " --clear=minimal (DANGEROUS) clear only overwritten free blocks\n" " after remapping\n" " --clear=none (DANGEROUS) do not clear any free blocks after remapping\n" " --cmd-umount=CMD command to unmount %s (default: /bin/umount)\n" " --cmd-losetup=CMD 'losetup' command (default: /sbin/losetup)\n" " --color=MODE set messages color. MODE is one of:\n" " auto (default), none, ansi\n" #ifdef FT_HAVE_IO_PREALLOC " --device-mount-point=DIR\n" " set device mount point (needed by --io=prealloc)\n" #endif " -f, --force-run continue even if some sanity checks fail\n" " -i, --interactive ask confirmation after analysis, before actual work\n" " --io=posix use posix I/O (default)\n" #ifdef FT_HAVE_IO_PREALLOC " --io=prealloc use posix I/O with EXPERIMENTAL preallocated files\n" #endif " --io=self-test perform in-memory self-test with random data\n" " --io=test use test I/O. Arguments are:\n" " DEVICE-LENGTH LOOP-FILE-EXTENTS FREE-SPACE-EXTENTS\n" #ifdef FT_HAVE_IO_PREALLOC " --loop-device=LOOP-DEVICE\n" " loop device to disconnect (needed by --io=prealloc)\n" " --loop-mount-point=DIR\n" " set loop file mount point (needed by --io=prealloc)\n" #endif " -m, --mem-buffer=RAM_SIZE[k|M|G|T|P|E|Z|Y]\n" " set RAM buffer size (default: autodetect)\n" " -n, --no-action, --simulate-run\n" " do not actually read or write any disk block\n" " --questions=MODE set interactive mode. MODE is one of:\n" " no: never ask questions, abort on errors (default)\n" " yes: ask questions in case of user-fixable errors\n" " extra: also ask confirmation before dangerous steps\n" " -q, --quiet be quiet, print less output\n" " -qq be very quiet, only print warnings or errors\n" " --resume-job=NUM resume the interrupted job NUM. The only non-option\n" " argument must be %s. Do _not_ pass %s\n" " as argument, or you will LOSE YOUR DATA!\n" " -s, --secondary-storage=SECONDARY_SIZE[k|M|G|T|P|E|Z|Y]\n" " set secondary storage file length (default: autodetect)\n" " -t, --temp-dir=DIR write storage and log files inside DIR\n" " (default: /var/tmp/fstransform)\n" " --ui-tty=TTY show full-text progress on tty device TTY\n" " -v, --verbose be verbose\n" " -vv be very verbose\n" " -vvv be incredibly verbose (warning: prints lots of output)\n" " -xp, --exact-primary-storage=PRIMARY_SIZE[k|M|G|T|P|E|Z|Y]\n" " set _exact_ primary storage length, or fail\n" " (default: autodetect)\n" " -xs, --exact-secondary-storage=SECONDARY_SIZE[k|M|G|T|P|E|Z|Y]\n" " set _exact_ secondary storage length, or fail\n" " (default: autodetect)\n" " --x-OPTION=VALUE set internal, undocumented option. for maintainers only\n" " --help display this help and exit\n" " --version output version information and exit\n", LABEL[FC_DEVICE], LABEL[FC_DEVICE], LABEL[FC_LOOP_FILE]); } /** output version information and return 0 */ int fr_remap::version() { quit_immediately = true; return ff_log(FC_NOTICE, 0, "fsremap (fstransform utilities) " FT_VERSION "\n" "Copyright (C) 2011-2017 Massimiliano Ghilardi\n" "\n" "License GPLv3+: GNU GPL version 3 or later .\n" "This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law.\n"); } int fr_remap::invalid_cmdline(const fr_args & args, int err, const char * fmt, ...) { va_list vargs; va_start(vargs, fmt); err = ff_vlog(FC_ERROR, err, fmt, vargs); va_end(vargs); ff_log(FC_NOTICE, 0, "Try `%s --help' for more information", args.program_name); /* mark error as reported */ return err ? err : -EINVAL; } /** return EISCONN if remapper is initialized, else call quit_io() and return 0 */ int fr_remap::check_is_closed() { int err = 0; if (is_initialized()) { ff_log(FC_ERROR, 0, "error: I/O subsystem already started"); /* error is already reported, flip sign */ err = -EISCONN; } else // quit_io() to make sure we are not left in a half-initialized status // (this_io != NULL && !this_io->is_open()) quit_io(); return err; } /** return 0 if remapper is initialized, else ENOTCONN */ int fr_remap::check_is_open() { int err = 0; if (!is_initialized()) { ff_log(FC_ERROR, 0, "error: I/O subsystem not started"); // quit_io() to make sure we are not left in a half-initialized status // (this_io != NULL && !this_io->is_open()) quit_io(); /* error is already reported, flip sign */ err = -ENOTCONN; } return err; } static ft_size ff_str_index_of_plus_1(const char * haystack, char needle) { const char * match = strchr(haystack, (int) needle); if (match != NULL) return match - haystack + 1; return strlen(haystack); } /** * parse from command line and initialize all subsystems (job, I/O, log...) * return 0 if success, else error. * * implementation: parse command line, fill a fr_args and call init(const fr_args &) */ int fr_remap::init(int argc, char const* const* argv) { fr_args args; int err; fr_io_kind io_kind; fr_clear_free_space new_clear; ft_log_fmt format = FC_FMT_MSG; ft_log_level level = FC_INFO, new_level; ft_log_color color = FC_COL_AUTO; bool format_set = false; do { if ((err = check_is_closed()) != 0) break; if (argc == 0) { err = invalid_cmdline(args, 0, "missing arguments: %s %s [%s]", LABEL[0], LABEL[1], LABEL[2]); break; } const char * arg; ft_size io_args_n = 0; bool allow_opts = true; args.program_name = argv[0]; // skip program_name while (err == 0 && --argc) { arg = * ++argv; if (allow_opts && arg[0] == '-') { ft_size opt_len = ff_str_index_of_plus_1(arg, '='); bool is_short_opt = arg[1] != '-'; const char * opt_arg = argc > 1 && is_short_opt ? argv[1] : arg + opt_len; /* -- means end of options*/ if (!strcmp(arg, "--")) allow_opts = false; /* -a, --no-questions run automatically without asking any confirmation */ else if (!strcmp(arg, "-a") || !strcmp(arg, "--no-questions")) { args.ask_questions = false; } /* --clear=all, --clear=minimal, --clear=none */ else if ((new_clear = FC_CLEAR_ALL, !strcmp(arg, "--clear=all")) || (new_clear = FC_CLEAR_MINIMAL, !strcmp(arg, "--clear=minimal")) || (new_clear = FC_CLEAR_NONE, !strcmp(arg, "--clear=none"))) { if (args.job_clear == FC_CLEAR_AUTODETECT) args.job_clear = new_clear; else err = invalid_cmdline(args, 0, "options --clear=all, --clear=minimal and --clear=none are mutually exclusive"); } /* --cmd-losetup=CMD */ else if (!strncmp(arg, "--cmd-losetup=", opt_len)) { args.cmd_losetup = opt_arg; } /* --cmd-umount=CMD */ else if (!strncmp(arg, "--cmd-umount=", opt_len)) { args.cmd_umount = opt_arg; } /* -f, --force-run: consider failed sanity checks as WARNINGS (which let execution continue) instead of ERRORS (which stop execution) */ else if (!strcmp(arg, "-f") || !strcmp(arg, "--force-run")) { args.force_run = true; } /* -i, --interactive: ask confirmation after analysis, before starting real work */ else if (!strcmp(arg, "-i") || !strcmp(arg, "--interactive")) { args.ask_questions = true; } /* --io=test, --io=self-test, --io=posix, --io=prealloc */ else if ((io_kind = FC_IO_TEST, !strcmp(arg, "--io=test")) || (io_kind = FC_IO_SELF_TEST, !strcmp(arg, "--io=self-test")) || (io_kind = FC_IO_POSIX, !strcmp(arg, "--io=posix")) #ifdef FT_HAVE_IO_PREALLOC || (io_kind = FC_IO_PREALLOC, !strcmp(arg, "--io=prealloc")) #endif ) { if (args.io_kind == FC_IO_AUTODETECT) args.io_kind = io_kind; else err = invalid_cmdline(args, 0, "options --io=posix, --io=prealloc, --io=test and --io=self-test are mutually exclusive"); } else if (!strncmp(arg, "--loop-device=", opt_len)) { args.loop_dev = opt_arg; } /* -m, --mem-buffer=RAM_SIZE[k|M|G|T|P|E|Z|Y] */ else if ((argc > 1 && !strcmp(arg, "-m")) || !strncmp(arg, "--mem-buffer=", opt_len)) { if ((err = ff_str2un_scaled(opt_arg, & args.storage_size[FC_MEM_BUFFER_SIZE])) != 0) { err = invalid_cmdline(args, err, "invalid memory buffer size '%s'", opt_arg); break; } if (is_short_opt) --argc, ++argv; } else if (!strncmp(arg, "--device-mount-point=", opt_len)) { args.mount_points[FC_MOUNT_POINT_DEVICE] = opt_arg; } else if (!strncmp(arg, "--loop-mount-point=", opt_len)) { args.mount_points[FC_MOUNT_POINT_LOOP_FILE] = opt_arg; } /* -n, --no-action, --simulate-run: do not read or write device blocks */ else if (!strcmp(arg, "-n") || !strcmp(arg, "--no-action") || !strcmp(arg, "--simulate-run")) { args.simulate_run = true; } /* --questions=[no|yes|extra] */ else if (!strncmp(arg, "--questions=", opt_len)) { args.ask_questions = !strcmp("extra", opt_arg); } /* --resume-job=JOB_ID */ else if (!strncmp(arg, "--resume-job=", opt_len)) { if (args.job_id != FC_JOB_ID_AUTODETECT) { err = invalid_cmdline(args, err, "option --resume-job=JOB_ID can be specified only once"); break; } if ((err = ff_str2un(opt_arg, & args.job_id)) != 0 || args.job_id == FC_JOB_ID_AUTODETECT) { err = invalid_cmdline(args, err, "invalid job id '%s'", opt_arg); break; } if (is_short_opt) --argc, ++argv; } /* -s, --secondary-storage=SECONDARY_SIZE[k|M|G|T|P|E|Z|Y] */ else if ((argc > 1 && !strcmp(arg, "-s")) || !strncmp(arg, "--secondary-storage=", opt_len)) { if ((err = ff_str2un_scaled(opt_arg, & args.storage_size[FC_SECONDARY_STORAGE_SIZE])) != 0) { err = invalid_cmdline(args, err, "invalid secondary storage size '%s'", opt_arg); break; } if (is_short_opt) --argc, ++argv; } /* -t, --temp-dir=DIR */ else if ((argc > 1 && !strcmp(arg, "-t")) || !strncmp(arg, "--temp-dir=", opt_len)) { args.root_dir = opt_arg; if (is_short_opt) --argc, ++argv; } /* --ui-tty=TTY */ else if (!strncmp(arg, "--ui-tty=", opt_len)) { args.ui_kind = FC_UI_TTY; args.ui_arg = opt_arg; } /* -xp, --exact-primary-storage=PRIMARY_SIZE[k|M|G|T|P|E|Z|Y] */ else if ((argc > 1 && !strcmp(arg, "-xp")) || !strncmp(arg, "--exact-primary-storage=", opt_len)) { if ((err = ff_str2un_scaled(opt_arg, & args.storage_size[FC_PRIMARY_STORAGE_EXACT_SIZE])) != 0) { err = invalid_cmdline(args, err, "invalid primary storage exact size '%s'", opt_arg); break; } if (is_short_opt) --argc, ++argv; } /* -xs, --exact-secondary-storage=SECONDARY_SIZE[k|M|G|T|P|E|Z|Y] */ else if ((argc > 1 && !strcmp(arg, "-xs")) || !strncmp(arg, "--exact-secondary-storage=", opt_len)) { if ((err = ff_str2un_scaled(opt_arg, & args.storage_size[FC_SECONDARY_STORAGE_EXACT_SIZE])) != 0) { err = invalid_cmdline(args, err, "invalid secondary storage exact size '%s'", opt_arg); break; } if (is_short_opt) --argc, ++argv; } /* --x-log-FILE=LEVEL */ else if (!strncmp(arg, "--x-log-", 8)) { ft_mstring logger_name(arg + 8, opt_len - 9); // 9 == 8 for "--x-log-" plus 1 for '=' ft_log_level logger_level = (ft_log_level) atoi(opt_arg); ft_log::get_logger(logger_name).set_level(logger_level); } /* -q, --quiet decrease verbosity by one */ /* -qq decrease verbosity by two */ /* -v, --verbose increase verbosity by one */ /* -vv increase verbosity by two */ /* -vvv increase verbosity by three */ else if ((new_level = FC_WARN, !strcmp(arg, "-qq")) || (new_level = FC_NOTICE, !strcmp(arg, "-q") || !strcmp(arg, "--quiet")) || (new_level = FC_DEBUG, !strcmp(arg, "-v") || !strcmp(arg, "--verbose")) || (new_level = FC_TRACE, !strcmp(arg, "-vv")) || (new_level = FC_DUMP, !strcmp(arg, "-vvv"))) { if (level == FC_INFO) level = new_level; else { err = invalid_cmdline(args, 0, "options -q, -qq, -v, -vv, -vvv, --quiet, --verbose are mutually exclusive"); break; } } else if (!strncmp(arg, "--log-color=", 12)) { /* --color=(auto|none|ansi) */ arg += 12; if (!strcmp(arg, "ansi")) color = FC_COL_ANSI; else if (!strcmp(arg, "none")) color = FC_COL_NONE; else color = FC_COL_AUTO; } else if (!strncmp(arg, "--log-format=", 13)) { /* --color=(auto|none|ansi) */ arg += 13; if (!strcmp(arg, "level_msg")) format = FC_FMT_LEVEL_MSG; else if (!strcmp(arg, "time_level_msg")) format = FC_FMT_DATETIME_LEVEL_MSG; else if (!strcmp(arg, "time_level_function_msg")) format = FC_FMT_DATETIME_LEVEL_CALLER_MSG; else format = FC_FMT_MSG; format_set = true; } else if (!strcmp(arg, "--help")) { return usage(args.program_name); } else if (!strcmp(arg, "--version")) { return version(); } else { err = invalid_cmdline(args, 0, "unknown option: '%s'", arg); break; } continue; } /** found an argument */ if (io_args_n < FC_FILE_COUNT) args.io_args[io_args_n++] = arg; else err = invalid_cmdline(args, 0, "too many arguments"); } if (err != 0) break; /* if autodetect, clear all free blocks */ if (args.job_clear == FC_CLEAR_AUTODETECT) args.job_clear = FC_CLEAR_ALL; /* if autodetect, use POSIX I/O */ if (args.io_kind == FC_IO_AUTODETECT) args.io_kind = FC_IO_POSIX; if (args.io_kind == FC_IO_POSIX || args.io_kind == FC_IO_PREALLOC) { if (args.job_id == FC_JOB_ID_AUTODETECT) { if (io_args_n == 0) { err = invalid_cmdline(args, 0, "missing arguments: %s %s [%s]", LABEL[0], LABEL[1], LABEL[2]); } else if (io_args_n == 1) { err = invalid_cmdline(args, 0, "missing arguments: %s [%s]", LABEL[1], LABEL[2]); } else if (io_args_n == 2 || io_args_n == 3) { /* ok */ } else err = invalid_cmdline(args, 0, "too many arguments"); } else { if (io_args_n == 0) { err = invalid_cmdline(args, 0, "missing argument: %s", LABEL[0]); } else if (io_args_n == 1) { /* ok */ } else err = invalid_cmdline(args, 0, "too many arguments"); } } else if (args.io_kind == FC_IO_TEST) { if (io_args_n == 0) { err = invalid_cmdline(args, 0, "missing arguments: %s %s %s", LABEL[0], LABEL[1], LABEL[2]); } else if (io_args_n == 1) { err = invalid_cmdline(args, 0, "missing arguments: %s %s", LABEL[1], LABEL[2]); } else if (io_args_n == 2) { err = invalid_cmdline(args, 0, "missing argument: %s", LABEL[2]); } else if (io_args_n == 3) { /* ok */ } else err = invalid_cmdline(args, 0, "too many arguments"); } } while (0); if (err == 0) { ff_log(FC_INFO, 0, "setting log level to %s", ff_log_level_to_string(level)); /* * always enable at least DEBUG level, to let let the appender installed by fr_job::init_log() * intercept all messages from DEBUG to FATAL. * we avoid spamming the user by setting stdout appender->min_level = level below */ ft_log::get_root_logger().set_level(level < FC_DEBUG ? level : FC_DEBUG); /* note 1.4.1) -v sets format FC_FMT_LEVEL_MSG */ /* note 1.4.2) -vv sets format FC_FMT_DATETIME_LEVEL_MSG */ if (!format_set) format = level < FC_DEBUG ? FC_FMT_DATETIME_LEVEL_MSG : level == FC_DEBUG ? FC_FMT_LEVEL_MSG : FC_FMT_MSG; // set stdout appender->min_level, since we played tricks with root_logger->level above. ft_log_appender::reconfigure_all(format, level, color); err = init(args); } return err; } /** * initialize all subsystems (job, I/O, log...) using specified arguments * return 0 if success, else error. */ int fr_remap::init(const fr_args & args) { int err; do { if ((err = init_job_persist(args)) != 0) break; if ((err = init_ui(args)) != 0) break; if ((err = init_io(args)) != 0) break; } while (0); return err; } /** initialize job/persistence subsystem */ int fr_remap::init_job_persist(const fr_args & args) { fr_job * job = this_job; FT_IO_NS fr_persist * persist = this_persist; int err = 0; if ((job == NULL) != (persist == NULL)) { ff_log(FC_FATAL, 0, "BUG! half-initialized state detected in init_job_persist(): job %s NULL, persist %s NULL", (job == NULL ? "==" : "!="), (persist == NULL ? "==" : "!=")); return -EINVAL; } if (job == NULL) { job = new fr_job(); if ((err = job->init(args)) != 0) { quit_job_persist(); return err; } } if (persist == NULL) { persist = new FT_IO_NS fr_persist(* job); if ((err = persist->open()) != 0) { quit_job_persist(); return err; } } this_job = job; this_persist = persist; return err; } /** quit job/persistence subsystem */ void fr_remap::quit_job_persist() { delete this_persist; delete this_job; this_persist = NULL; this_job = NULL; quit_immediately = false; } /** initialize UI subsystem */ int fr_remap::init_ui(const fr_args & args) { if (this_ui != NULL) { ff_log(FC_ERROR, 0, "unexpected call to init_ui(): UI subsystem is already initialized"); /* mark error as reported */ return -EISCONN; } int err; switch (args.ui_kind) { case FC_UI_NONE: err = 0; break; case FC_UI_TTY: err = init_ui_tty(args.ui_arg); break; default: ff_log(FC_ERROR, 0, "tried to initialize unknown UI '%d': not tty", (int) args.ui_kind); err = -ENOSYS; break; } return err; } /** initialize UI subsystem */ int fr_remap::init_ui_tty(const char * arg) { FT_UI_NS fr_ui_tty * ui_tty = new FT_UI_NS fr_ui_tty(); int err = ui_tty->init(arg); if (err == 0) this_ui = ui_tty; else delete ui_tty; return err; } /** quit UI subsystem */ void fr_remap::quit_ui() { delete this_ui; this_ui = NULL; } /** * choose the I/O to use, create and initialize it. if success, stores a pointer to I/O object. * * return 0 if success, else error. */ int fr_remap::init_io(const fr_args & args) { int err; switch (args.io_kind) { case FC_IO_TEST: err = init_io_class(args); break; case FC_IO_SELF_TEST: err = init_io_class(args); break; case FC_IO_POSIX: err = init_io_class(args); break; #ifdef FT_HAVE_IO_PREALLOC case FC_IO_PREALLOC: err = init_io_class(args); break; #endif default: ff_log(FC_ERROR, 0, "tried to initialize unknown I/O '%d': not POSIX, not PREALLOC, not TEST, not SELF-TEST", (int) args.io_kind); err = -ENOSYS; break; } return err; } /** * initialize remapper to use I/O type IO_T. * * args depend on I/O type: * POSIX and PREALLOC I/O require two or three arguments in args.io_args: DEVICE, LOOP-FILE and optionally ZERO-FILE; * test I/O requires three arguments in args.io_args: DEVICE-LENGTH, LOOP-FILE-EXTENTS and ZERO-FILE-EXTENTS; * self-test I/O does not require any argument in args.io_args; * return 0 if success, else error. */ template int fr_remap::init_io_class(const fr_args & args) { int err; if ((err = pre_init_io()) == 0) { IO_T * io = new IO_T(* this_persist); if ((err = io->open(args)) == 0) post_init_io(io); else delete io; } return err; } int fr_remap::pre_init_io() { int err = check_is_closed(); if (err == 0 && this_persist == NULL) { ff_log(FC_ERROR, 0, "error: cannot start I/O subsystem, persistence must be initialized first"); err = -ENOTCONN; } return err; } void fr_remap::post_init_io(FT_IO_NS fr_io * io) { this_io = io; io->ui(this_ui); } /** shutdown remapper. closes configured I/O and deletes it */ void fr_remap::quit_io() { delete this_io; this_io = NULL; } /** * perform actual work using configured I/O: * allocates fr_vector for both LOOP-FILE and FREE-SPACE extents, * calls this_io->read_extents() to fill them, and finally invokes * fr_dispatch::main(loop_file_extents, free_space_extents, this_io) * * return 0 if success, else error. */ int fr_remap::run() { int err = 0; do { if ((err = check_is_open()) != 0) break; FT_IO_NS fr_io & io = * this_io; const char * dev_path = ff_if_null(io.dev_path(), ""); ff_log(FC_INFO, 0, "analyzing %s '%s', this may take some minutes ...", label[FC_DEVICE], dev_path); /* allocate fr_vector for both LOOP-FILE and FREE-SPACE extents */ fr_vector loop_file_extents, free_space_extents; // preallocated extents in files inside loop file // which do NOT have a correspondence in files inside device: // they must be cleared once remapping is completed! fr_vector to_zero_extents; /* ask actual I/O subsystem to read LOOP-FILE and FREE-SPACE extents */ if ((err = io.read_extents(loop_file_extents, free_space_extents, to_zero_extents)) != 0) break; /* persistence: save LOOP-FILE and FREE-SPACE extents to disk */ if ((err = io.save_extents(loop_file_extents, free_space_extents, to_zero_extents)) != 0) break; io.close_extents(); /* invoke fr_dispatch::main() to choose which fr_work to instantiate, and run it */ err = fr_dispatch::main(loop_file_extents, free_space_extents, to_zero_extents, io); } while (0); return err; } FT_NAMESPACE_END fstransform-0.9.4/fsremap/src/remap.hh000066400000000000000000000112511345021500300177320ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * remap.hh * * Created on: Feb 28, 2011 * Author: max */ #ifndef FSREMAP_REMAP_HH #define FSREMAP_REMAP_HH #include "check.hh" #include "args.hh" // for fr_args #include "io/persist.hh" // for fr_persist #include "io/io.hh" // for fr_io #include "io/io_posix.hh" // for fr_io_posix #include "io/io_test.hh" // for fr_io_test #include "ui/ui.hh" // for fr_ui #include "ui/ui_tty.hh" // for fr_ui_tty FT_NAMESPACE_BEGIN class fr_remap { private: fr_job * this_job; FT_IO_NS fr_persist * this_persist; FT_IO_NS fr_io * this_io; FT_UI_NS fr_ui * this_ui; /** true if usage() or version() was called. */ bool quit_immediately; /** cannot call copy constructor */ fr_remap(const fr_remap &); /** cannot call assignment operator */ const fr_remap & operator=(const fr_remap &); /** display command-line usage to stdout and return 0 */ int usage(const char * program_name); /** output version information and return 0 */ int version(); static int invalid_cmdline(const fr_args & args, int err, const char * fmt, ...); /** return EISCONN if remapper is initialized, else call quit_io() and return 0 */ int check_is_closed(); /** return 0 if remapper is initialized, else call quit_io() and return ENOTCONN */ int check_is_open(); /** initialize job/persistence subsystem */ int init_job_persist(const fr_args & argsd); /** quit job/persistence subsystem */ void quit_job_persist(); /** initialize UI subsystem */ int init_ui(const fr_args & args); /** initialize tty UI subsystem */ int init_ui_tty(const char * arg); /** quit UI subsystem */ void quit_ui(); int pre_init_io(); /** * initialize remapper to use I/O type IO_T. * * args depend on I/O type: * POSIX and PREALLOC I/O require two or three arguments in args.io_args: DEVICE, LOOP-FILE and optionally ZERO-FILE; * test I/O requires three arguments in args.io_args: DEVICE-LENGTH, LOOP-FILE-EXTENTS and ZERO-FILE-EXTENTS; * self-test I/O does not require any argument in args.io_args; * return 0 if success, else error. */ template int init_io_class(const fr_args & args); void post_init_io(FT_IO_NS fr_io * io); public: /** constructor */ fr_remap(); /** destructor. calls quit_io() */ ~fr_remap(); /** * high-level main method. * calls in sequence: init(argc, argv), run(), quit_io() * * expects argc == 4 and four arguments in argv: * program_name, DEVICE, LOOP-FILE and ZERO-FILE. * * return 0 if success, else error. * if invoked with the only argument "--help", calls usage() and immediately returns 0 */ static int main(int argc, char const* const* argv); FT_INLINE bool is_initialized() const { return this_io != NULL && this_io->is_open(); } /** * parse from command line and initialize all subsystems (job, I/O, log...) * return 0 if success, else error. * * implementation: parse command line, fill a fr_args and call init(const fr_args &) */ int init(int argc, char const* const* argv); /** * initialize all subsystems (job, I/O, log...) using specified arguments * return 0 if success, else error. */ int init(const fr_args & args); /** * allocate, open and use I/O specified in args. * if success, stores a pointer to I/O object * destructor and quit_io() will delete fr_io object. * * return 0 if success, else error. */ int init_io(const fr_args & args); /** * perform actual work using configured I/O * return 0 if success, else error. */ int run(); /** close configured I/O and delete it */ void quit_io(); }; FT_NAMESPACE_END #endif /* FSREMAP_REMAP_HH */ fstransform-0.9.4/fsremap/src/tmp_zero.cc000066400000000000000000000123721345021500300204600ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * tmp_zero.cc * * Created on: Mar 27, 2011 * Author: max */ #include "first.hh" #if defined(FT_HAVE_STDIO_H) # include // for fopen(), fclose() #elif defined(FT_HAVE_CSTDIO) # include // for fopen(), fclose() #endif #if defined(FT_HAVE_STRING_H) # include // for memset() #elif defined(FT_HAVE_CSTRING) # include // for memset() #endif #ifdef FT_HAVE_SYS_TYPES_H # include // for open() #endif #ifdef FT_HAVE_SYS_STAT_H # include // " " #endif #ifdef FT_HAVE_FCNTL_H # include // " " #endif #ifdef FT_HAVE_UNISTD_H # include // for close() #endif #include "log.hh" // for ff_log() #include "misc.hh" // for ff_str2un(), ff_min2() #include "map.hh" // for fr_map #include "vector.hh" // for fr_vector #include "work.hh" // for fr_work::show() #include "io/extent_file.hh" // for ff_load_extents_file() #include "io/util_posix.hh" // for ff_posix_write() FT_IO_NAMESPACE_BEGIN #ifdef FR_TEST_WRITE_ZEROES /** * argv[0] = program_name * argv[1] = device length * argv[2] = save-file containing loop-file extents */ int ff_zero_loop_file_holes(int argc, char ** argv) { ft_uoff dev_len; FILE * f = NULL; char const* const* const args = argv + 1; int dev_fd = -1, err; do { if (argc <= 2) { ff_log(FC_ERROR, 0, "Usage: %s DEVICE FILE", argv[0]); err = -EINVAL; break; } if ((dev_fd = ::open(args[0], O_RDWR)) < 0) { err = ff_log(FC_ERROR, errno, "error opening device '%s'", args[0]); break; } if ((err = ff_posix_blkdev_size(dev_fd, & dev_len)) != 0) { ff_log(FC_WARN, errno, "warning: device ioctl('%s', BLKGETSIZE64) failed, trying fstat() to get device length", args[0]); if ((err = ff_posix_size(dev_fd, & dev_len)) != 0) { err = ff_log(FC_ERROR, errno, "error in device fstat('%s')", args[0]); break; } } if ((f = fopen(args[1], "r")) == NULL) { err = ff_log(FC_ERROR, errno, "error opening persistence file '%s'", args[1]); break; } fr_vector loop_extents; ft_uoff block_size_bitmask = 0; if ((err = ff_load_extents_file(f, loop_extents, block_size_bitmask)) != 0) { err = ff_log(FC_ERROR, err, "error reading persistence file '%s'"); break; } ft_uoff eff_block_size_log2 = 0; if (block_size_bitmask != 0) { while ((block_size_bitmask & 1) == 0) { eff_block_size_log2++; block_size_bitmask >>= 1; } } fr_map loop_holes_map; loop_holes_map.complement0_logical_shift(loop_extents, eff_block_size_log2, dev_len); fr_work::show("loop-holes", "", eff_block_size_log2, loop_holes_map, FC_INFO); fr_map::const_iterator iter = loop_holes_map.begin(), end = loop_holes_map.end(); enum { ZERO_BUF_LEN = 1024*1024 }; char zero_buf[ZERO_BUF_LEN]; memset(zero_buf, '\0', ZERO_BUF_LEN); ft_uoff offset, left, chunk; for (; iter != end; ++iter) { const fr_map::value_type & extent = *iter; offset = extent.first.physical << eff_block_size_log2; left = extent.second.length << eff_block_size_log2; if ((err = ff_posix_lseek(dev_fd, offset)) != 0) { err = ff_log(FC_ERROR, err, "error in device lseek('%s', offset = %" FT_ULL ")", args[0], (ft_ull) offset); break; } while (left != 0) { chunk = ff_min2(left, ZERO_BUF_LEN); if ((err = ff_posix_write(dev_fd, zero_buf, chunk)) != 0) { err = ff_log(FC_ERROR, err, "error in device write({'%s', offset = %" FT_ULL "}, zero_buffer, length = %" FT_ULL ")", args[0], (ft_ull) offset, (ft_ull) chunk); break; } left -= chunk; } } } while (0); if (f != NULL) fclose(f); if (dev_fd >= 0) close(dev_fd); return err; } #endif /* FR_TEST_WRITE_ZEROES */ FT_IO_NAMESPACE_END fstransform-0.9.4/fsremap/src/traits.hh000066400000000000000000000056651345021500300201500ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * traits.hh * * Created on: Feb 27, 2011 * Author: max */ #ifndef FSTRANSFORM_TRAITS_HH #define FSTRANSFORM_TRAITS_HH #include "check.hh" FT_NAMESPACE_BEGIN template struct ft_type_traits; /** * whether char is signed or unsigned is implementation dependent. * in any case, the compiler treats (char), (unsigned char) and (signed char) as different types */ template<> struct ft_type_traits { typedef unsigned char unsigned_type; typedef signed char signed_type; }; template<> struct ft_type_traits { typedef unsigned char unsigned_type; typedef signed char signed_type; }; template<> struct ft_type_traits { typedef unsigned char unsigned_type; typedef signed char signed_type; }; template<> struct ft_type_traits { typedef unsigned short unsigned_type; typedef short signed_type; }; template<> struct ft_type_traits { typedef unsigned short unsigned_type; typedef short signed_type; }; template<> struct ft_type_traits { typedef unsigned int unsigned_type; typedef int signed_type; }; template<> struct ft_type_traits { typedef unsigned int unsigned_type; typedef int signed_type; }; template<> struct ft_type_traits { typedef unsigned long unsigned_type; typedef long signed_type; }; template<> struct ft_type_traits { typedef unsigned long unsigned_type; typedef long signed_type; }; #ifdef FT_HAVE_LONG_LONG template<> struct ft_type_traits { typedef unsigned long long unsigned_type; typedef long long signed_type; }; template<> struct ft_type_traits { typedef unsigned long long unsigned_type; typedef long long signed_type; }; #endif /* FT_HAVE_LONG_LONG */ #define FT_TYPE_TO_UNSIGNED(T) FT_NS ft_type_traits< T >::unsigned_type #define FT_TYPE_TO_SIGNED(T) FT_NS ft_type_traits< T >::signed_type FT_NAMESPACE_END #endif /* FSTRANSFORM_TRAITS_HH */ fstransform-0.9.4/fsremap/src/types.hh000066400000000000000000000076621345021500300200050ustar00rootroot00000000000000/* * common types for fsattr, fsmove, fsremap * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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, see . * * types.hh * * Created on: Feb 14, 2011 * Author: max */ #ifndef FSTRANSFORM_TYPES_HH #define FSTRANSFORM_TYPES_HH #include "check.hh" #if defined(FT_HAVE_STDDEF_H) # include // for size_t #elif defined(FT_HAVE_CSTDDEF) # include // for size_t #endif #if defined(FT_HAVE_STDINT_H) # include // for uint64_t, uint32_t #elif defined(FT_HAVE_CSTDINT) # include // for uint64_t, uint32_t #endif #ifdef FT_HAVE_SYS_TYPES_H # include // for off_t, pid_t, mode_t, ino_t #endif #ifdef FT_HAVE_SYS_STAT_H # include // for struct stat #endif #ifdef FT_HAVE_UNISTD_H # include // " " " #endif #include // for std::string #include "traits.hh" // for FT_TYPE_TO_UNSIGNED // ft_size is the type used to represent number of items in memory. when size_t exists, they must be the same type typedef size_t ft_size; // ft_ssize is the signed version of ft_size. when ssize_t exists, they must be the same type typedef ssize_t ft_ssize; // ft_off is the type used to represent files length and block devices length. when off_t exists, they must be the same type typedef off_t ft_off; // ft_u64 must be exactly 64-bit unsigned integer. used for ioctl(FS_IOC_FIEMAP), ioctl(BLKGETSIZE64), e4_cpu2fs() and e4_fs2cpu() typedef uint64_t ft_u64; // ft_u32 must be exactly 32-bit unsigned integer. used for ioctl(FS_IOC_FIEMAP), e4_cpu2fs() and e4_fs2cpu() typedef uint32_t ft_u32; // ft_i32 must be exactly 32-bit signed integer. used for ft_rope_impl typedef int32_t ft_i32; // ft_u16 must be exactly 16-bit unsigned integer. only used for e4_cpu2fs() and e4_fs2cpu() typedef uint16_t ft_u16; // ft_u8 must be exactly 8-bit unsigned integer. only used for e4_cpu2fs() and e4_fs2cpu() typedef uint8_t ft_u8; // ft_dev is the type used for ID of block devices. when dev_t exists, they must be the same type typedef dev_t ft_dev; // ft_mode is the type used for file/directory permissions. when mode_t exists, they must be the same type typedef mode_t ft_mode; // ft_inode is the type used for inode numbers. when ino_t exists, they must be the same type typedef ino_t ft_inode; // ft_nlink is the type used for inode link count. when nlink_t exists, they must be the same type typedef nlink_t ft_nlink; // ft_uoff is the unsigned variant of ft_off (in case ft_off is unsigned, they will be the same type) typedef FT_TYPE_TO_UNSIGNED(ft_off) ft_uoff; // ft_uint is a medium-size unsigned integer: smaller than ft_uoff, // but large enough to store blocks count for many devices typedef unsigned int ft_uint; // ft_ull must be the largest unsigned integer type existing on the platform #ifdef FT_HAVE_LONG_LONG typedef unsigned long long ft_ull; # define FT_ULL "llu" # define FT_XLL "llx" # define FT_OLL "llo" /* octal */ #else typedef unsigned long ft_ull; # define FT_ULL "lu" # define FT_XLL "lx" # define FT_OLL "lo" /* octal */ #endif // ft_stat is the same as 'struct stat' typedef struct stat ft_stat; // ft_string must be functionally equivalent to 'std::string', i.e. have a compatible API typedef std::string ft_string; #endif /* FSTRANSFORM_TYPES_HH */ fstransform-0.9.4/fsremap/src/ui/000077500000000000000000000000001345021500300167225ustar00rootroot00000000000000fstransform-0.9.4/fsremap/src/ui/ui.cc000066400000000000000000000021561345021500300176520ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * ui/ui.cc * * Created on: Mar 23, 2011 * Author: max */ #include "../first.hh" #include "ui.hh" FT_UI_NAMESPACE_BEGIN /** default constructor */ fr_ui::fr_ui() { } /** destructor */ fr_ui::~fr_ui() { } FT_UI_NAMESPACE_END fstransform-0.9.4/fsremap/src/ui/ui.hh000066400000000000000000000035301345021500300176610ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * ui/ui.hh * * Created on: Mar 23, 2011 * Author: max */ #ifndef FSREMAP_UI_UI_HH #define FSREMAP_UI_UI_HH #include "../types.hh" // for ft_uoff #include "../fwd.hh" // for fr_vector forward declaration #include "../extent.hh" // for fr_dir FT_UI_NAMESPACE_BEGIN class fr_ui { private: /** cannot call copy constructor */ fr_ui(const fr_ui &); /** cannot call assignment operator */ const fr_ui & operator=(const fr_ui &); protected: /** default constructor */ fr_ui(); public: /** destructor */ virtual ~fr_ui(); virtual int start(FT_IO_NS fr_io * io) = 0; virtual void show_io_read(fr_from from, ft_uoff offset, ft_uoff length) = 0; virtual void show_io_write(fr_to to, ft_uoff offset, ft_uoff length) = 0; virtual void show_io_copy(fr_dir dir, ft_uoff from_physical, ft_uoff to_physical, ft_uoff length) = 0; virtual void show_io_flush() = 0; }; FT_UI_NAMESPACE_END #endif /* FSREMAP_UI_TTY_HH */ fstransform-0.9.4/fsremap/src/ui/ui_tty.cc000066400000000000000000000124001345021500300205430ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * ui/ui_tty.cc * * Created on: Mar 23, 2011 * Author: max */ #include "../first.hh" #if defined(FT_HAVE_ERRNO_H) # include // for errno #elif defined(FT_HAVE_CERRNO) # include // for errno #endif #ifdef FT_HAVE_TERMIOS_H # include // for TIOCGWINSZ, struct winsize #endif #ifdef FT_HAVE_SYS_IOCTL_H # include // for ioctl() #endif #ifdef FT_HAVE_SYS_TYPES_H # include #endif #ifdef FT_HAVE_SYS_STAT_H # include #endif #ifdef FT_HAVE_FCNTL_H # include #endif #include "../log.hh" // for ff_log #include "../vector.hh" // for fr_vector #include "../io/io.hh" // for fr_io #include "ui_tty.hh" FT_UI_NAMESPACE_BEGIN fr_ui_tty::fr_tty_window::fr_tty_window() : len(0), h0(0), h(0) { } /** default constructor */ fr_ui_tty::fr_ui_tty() : super_type(), this_dev(), this_storage(), this_w(0), this_h(0), this_file(NULL), need_clr(true) { } /** destructor */ fr_ui_tty::~fr_ui_tty() { } int fr_ui_tty::init(const char * tty_name) { #ifdef TIOCGWINSZ struct winsize wsz; int err = 0, fd = -1; do { if ((fd = ::open(tty_name, O_WRONLY|O_NOCTTY)) < 0) { err = ff_log(FC_ERROR, errno, "error opening tty '%s'", tty_name); break; } if ((err = ::ioctl(fd, TIOCGWINSZ, &wsz)) != 0) { err = ff_log(FC_ERROR, errno, "error in tty ioctl('%s', TIOCGWINSZ)", tty_name); break; } if ((this_file = fdopen(fd, "w")) == NULL) { err = ff_log(FC_ERROR, errno, "error in tty fdopen('%s', \"w\")", tty_name); break; } this_w = (ft_uint) wsz.ws_col; this_h = (ft_uint) wsz.ws_row; if ((unsigned short)this_w != wsz.ws_col || (unsigned short)this_h != wsz.ws_row) { err = ff_log(FC_ERROR, EOVERFLOW, "tty window size overflows for (ft_uint)"); break; } } while (0); if (err != 0) { if (this_file != NULL) { if (fclose(this_file) != 0) ff_log(FC_WARN, errno, "warning: closing tty '%s' failed", tty_name); this_file = NULL; } if (fd >= 0) close(fd); } return err; #else /* !TIOCGWINSZ */ return ENOSYS; #endif } int fr_ui_tty::start(FT_IO_NS fr_io * io) { ft_uoff dev_len = io->dev_length(), storage_len = io->job_storage_size(FC_PRIMARY_STORAGE_EXACT_SIZE) + io->job_storage_size(FC_SECONDARY_STORAGE_EXACT_SIZE); if ((this_dev.len = dev_len) == 0 || (this_storage.len = storage_len) == 0) return ff_log(FC_ERROR, EINVAL, "error: device length or storage length is zero"); this_storage.h0 = 0; this_storage.h = (ft_uint)(0.5 + (double)this_h * this_storage.len / (this_dev.len + this_storage.len)); if (this_storage.h == 0) this_storage.h = 1; this_dev.h0 = this_storage.h; this_dev.h = this_h - this_storage.h; return 0; } void fr_ui_tty::show_io_read(fr_from from, ft_uoff offset, ft_uoff length) { const fr_tty_window & window = from == FC_FROM_DEV ? this_dev : this_storage; show_io_op(false, window, offset, length); } void fr_ui_tty::show_io_write(fr_to to, ft_uoff offset, ft_uoff length) { const fr_tty_window & window = to == FC_TO_DEV ? this_dev : this_storage; show_io_op(true, window, offset, length); } void fr_ui_tty::show_io_copy(fr_dir dir, ft_uoff from_physical, ft_uoff to_physical, ft_uoff length) { show_io_read(ff_from(dir), from_physical, length); show_io_write(ff_to(dir), to_physical, length); } void fr_ui_tty::show_io_op(bool is_write, const fr_tty_window & window, ft_uoff offset, ft_uoff length) { if (need_clr) { need_clr = false; fputs("\033[2J", this_file); } ft_ull pos = (ft_ull)((double)offset * this_w * window.h / window.len); ft_ull len = (ft_ull)(((double)length * this_w * window.h + window.len - 1) / window.len); ft_ull y = pos / this_w, x = pos % this_w; fprintf(this_file, "\033[3%cm\033[%" FT_ULL ";%" FT_ULL "H", (int)(is_write ? '1' : '2'), y+1+window.h0, x+1); /* ANSI colors: 1 = red, 2 = green */ while (len >= 40) { len -= 40; fputs("########################################", this_file); } while (len-- != 0) putc('#', this_file); } void fr_ui_tty::show_io_flush() { fflush(this_file); need_clr = true; } FT_UI_NAMESPACE_END fstransform-0.9.4/fsremap/src/ui/ui_tty.hh000066400000000000000000000047221345021500300205650ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * gui/tty.hh * * Created on: Mar 23, 2011 * Author: max */ #ifndef FSREMAP_UI_UI_TTY_HH #define FSREMAP_UI_UI_TTY_HH #if defined (FT_HAVE_STDIO_H) # include // for FILE. also for fdopen() used in ui_tty.cc #elif defined(FT_HAVE_CSTDIO) # include // for FILE. also for fdopen() used in ui_tty.cc #endif #include "../fwd.hh" // for fr_io #include "../types.hh" // for ft_uint, ft_uoff #include "ui.hh" // for fr_ui FT_UI_NAMESPACE_BEGIN class fr_ui_tty : public fr_ui { private: typedef fr_ui super_type; struct fr_tty_window { ft_uoff len; ft_uint h0, h; fr_tty_window(); }; fr_tty_window this_dev, this_storage; ft_uint this_w, this_h; /*< tty width and height */ FILE * this_file; bool need_clr; /** cannot call copy constructor */ fr_ui_tty(const fr_ui_tty &); /** cannot call assignment operator */ const fr_ui_tty & operator=(const fr_ui_tty &); void show_io_op(bool is_write, const fr_tty_window & window, ft_uoff offset, ft_uoff length); public: /** default constructor */ fr_ui_tty(); /** destructor */ virtual ~fr_ui_tty(); int init(const char * tty_name); virtual int start(FT_IO_NS fr_io * io); virtual void show_io_read(fr_from from, ft_uoff offset, ft_uoff length); virtual void show_io_write(fr_to to, ft_uoff offset, ft_uoff length); virtual void show_io_copy(fr_dir dir, ft_uoff from_physical, ft_uoff to_physical, ft_uoff length); virtual void show_io_flush(); }; FT_UI_NAMESPACE_END #endif /* FSREMAP_UI_UI_TTY_HH */ fstransform-0.9.4/fsremap/src/unsorted_map.cc000066400000000000000000000036711345021500300213230ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * inode_cache.hh * * Created on: Aug 18, 2011 * Author: max */ #include "first.hh" #include "copy.hh" #if defined(FT_HAVE_STDIO_H) # include /* for snprintf() */ #elif defined(FT_HAVE_CSTDIO) && defined(__cplusplus) # include /* for snprintf() */ #endif FT_NAMESPACE_BEGIN void ff_set(ft_string & dst, const ft_string & src) { dst = src; } void ff_set(ft_string & dst, ft_ull src) { enum { maxlen = sizeof(ft_ull) * 3 + 1 }; dst.resize(maxlen); char * buf = &dst[0]; int delta = snprintf(buf, maxlen, "%" FT_XLL, src); dst.resize(delta > 0 ? delta : 0); } void ff_set(ft_ull & dst, const ft_string & src) { dst = 0; sscanf(src.c_str(), "%" FT_XLL, &dst); } void ff_cat(ft_string & dst, const ft_string & src) { dst += src; } void ff_cat(ft_string & dst, ft_ull src) { enum { maxlen = sizeof(ft_ull) * 3 + 1 }; size_t oldlen = dst.length(); dst.resize(oldlen + maxlen); char * buf = &dst[oldlen]; int delta = snprintf(buf, maxlen, "%" FT_XLL, src); dst.resize(oldlen + (delta > 0 ? delta : 0)); } FT_NAMESPACE_END fstransform-0.9.4/fsremap/src/unsorted_map.hh000066400000000000000000000026251345021500300213330ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * inode_cache.hh * * Created on: Aug 18, 2011 * Author: max */ #ifndef FSTRANSFORM_UNSORTED_MAP_HH #define FSTRANSFORM_UNSORTED_MAP_HH #include "check.hh" #if defined(FT_HAVE_STD_UNORDERED_MAP) # ifdef FT_HAVE_UNORDERED_MAP # include # endif # define ft_unsorted_map std::unordered_map #elif defined(FT_HAVE_STD_TR1_UNORDERED_MAP) # ifdef FT_HAVE_TR1_UNORDERED_MAP # include # endif # define ft_unsorted_map std::tr1::unordered_map #endif #endif /* FSTRANSFORM_UNSORTED_MAP_HH */ fstransform-0.9.4/fsremap/src/vector.cc000066400000000000000000000022201345021500300201120ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * vector.cc * * Created on: Feb 27, 2011 * Author: max */ #include "first.hh" // for FT_*TEMPLATE* macros */ #ifdef FT_HAVE_EXTERN_TEMPLATE # include "vector.t.hh" FT_TEMPLATE_INSTANTIATE(FT_TEMPLATE_vector_hh) #else #endif /* FT_HAVE_EXTERN_TEMPLATE */ fstransform-0.9.4/fsremap/src/vector.hh000066400000000000000000000127661345021500300201440ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * vector.hh * * Created on: Feb 27, 2011 * Author: max */ #ifndef FSREMAP_VECTOR_HH #define FSREMAP_VECTOR_HH #include "check.hh" #include // for std::vector */ #include "fwd.hh" // for fr_map #include "log.hh" // for ft_log_level, FC_SHOW_DEFAULT_LEVEL. also used by vector.t.hh for ff_log() #include "extent.hh" // for fr_extent FT_NAMESPACE_BEGIN template class fr_vector : public std::vector > { private: typedef std::vector > super_type; /** actual implementation of compose() below */ int compose0(const fr_vector & a2b, const fr_vector & a2c, T & ret_block_size_bitmask, fr_vector * unmapped = 0); public: typedef fr_extent_key key_type; typedef fr_extent_payload mapped_type; typedef typename super_type::value_type value_type; typedef typename super_type::iterator iterator; typedef typename super_type::const_iterator const_iterator; /** * append a single extent to this vector. * * if this vector is not empty * and specified extent ->physical is equal to last->physical + last->length * and specified extent ->logical is equal to last->logical + last->length * where 'last' is the last extent in this vector, * then merge the two extents * * otherwise append to this vector a new extent containing specified extent (physical, logical, length) */ void append(T physical, T logical, T length, ft_size user_data); /** * append a single extent to this vector. * * if this vector is not empty * and specified extent ->physical is equal to last->physical + last->length * and specified extent ->logical is equal to last->logical + last->length * where 'last' is the last extent in this vector, * then merge the two extents * * otherwise append to this vector a new extent containing specified extent (physical, logical, length, user_data) */ FT_INLINE void append(const typename value_type::super_type & extent) { append(extent.first.physical, extent.second.logical, extent.second.length, extent.second.user_data); } /** * append another extent vector to this vector. * * this method does not merge extents: the two lists of extents will be simply concatenated */ void append_all(const fr_vector & other); /** * reorder this vector in-place, sorting by physical */ void sort_by_physical(); void sort_by_physical(iterator from, iterator to); /** * reorder this vector in-place, sorting by logical */ void sort_by_logical(); void sort_by_logical(iterator from, iterator to); /** * reorder this vector in-place, sorting by reverse length (largest extents will be first) */ void sort_by_reverse_length(); void sort_by_reverse_length(iterator from, iterator to); /** * swap ->physical with ->logical in each extent of this vector. * Note: does NOT sort after swapping! */ void transpose(); /** * used by ft_io_prealloc. * * truncate at specified logical value */ void truncate_at_logical(T logical_end); /** * used by ft_io_prealloc. * * given a vector mapping a->b (v1) and a vector mapping a->c (v2), * compute the vector mapping b->c (v2) and append it to this vector. * * user_data will be copied from v1. * all extents in b not mapped to c will be added to 'unmapped' (if not NULL) * * a->b and a->c must be sorted by ->physical * returns error if a->b domain (range in a) is smaller than a->c domain (range in a) * and in particular if a->b has holes where a->c does not. */ FT_INLINE int compose(const fr_vector & a2b, const fr_vector & a2c, T & ret_block_size_bitmask, fr_vector & unmapped) { return compose0(a2b, a2c, ret_block_size_bitmask, & unmapped); } /** same as compose() above, but does not compute 'block_size_bitmask' and 'unmapped' */ FT_INLINE int compose(const fr_vector & a2b, const fr_vector & a2c) { T block_size_bitmask = 0; return compose0(a2b, a2c, block_size_bitmask); } /** print vector contents to log */ void show(const char * label1, const char * label2, ft_uoff effective_block_size, ft_log_level level = FC_SHOW_DEFAULT_LEVEL) const; }; FT_NAMESPACE_END #ifdef FT_HAVE_EXTERN_TEMPLATE # define FT_TEMPLATE_vector_hh(ft_prefix, T) ft_prefix class FT_NS fr_vector< T >; FT_TEMPLATE_DECLARE(FT_TEMPLATE_vector_hh) #else # include "vector.t.hh" #endif /* FT_HAVE_EXTERN_TEMPLATE */ #endif /* FSREMAP_VECTOR_HH */ fstransform-0.9.4/fsremap/src/vector.t.hh000066400000000000000000000240371345021500300204000ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * vector.t.hh * * Created on: Feb 27, 2011 * Author: max */ #include "first.hh" #include // for std::sort(), std::swap() #if defined(FT_HAVE_ERRNO_H) # include // for EINVAL #elif defined(FT_HAVE_CERRNO) # include // for EINVAL #endif #include "log.hh" // for ff_log() #include "misc.hh" // for ff_can_sum(), ff_min2() #include "vector.hh" // for fr_vector FT_NAMESPACE_BEGIN /** * append a single extent to this vector. * * if this vector is not empty * and specified extent ->physical is equal to last->physical + last->length * and specified extent ->logical is equal to last->logical + last->length * where 'last' is the last extent in this vector, * then merge the two extents * * otherwise append to this vector a new extent containing specified extent (physical, logical, length) */ template void fr_vector::append(T physical, T logical, T length, ft_size user_data) { if (!this->empty()) { value_type & last = this->back(); T & last_length = last.length(); if (last.physical() + last_length == physical && last.logical() + last_length == logical) { /* merge! */ last_length += length; return; } } /* we could use this->push_back() but creating its parameter with make_pair() is cumbersome */ this->resize(this->size() + 1); value_type & extent = this->back(); extent.physical() = physical; extent.logical() = logical; extent.length() = length; extent.user_data() = user_data; } /** * append another extent vector to this vector. * * this method does not merge extents: the two lists of extents will be simply concatenated */ template void fr_vector::append_all(const fr_vector & other) { if (this != & other) { this->insert(this->end(), other.begin(), other.end()); } else { /* should not happen, but it's a recoverable problem */ } } /** * reorder this vector in-place, sorting by physical */ template void fr_vector::sort_by_physical() { std::sort(this->begin(), this->end(), typename value_type::comparator_physical()); } /** * reorder this vector in-place, sorting by physical */ template void fr_vector::sort_by_physical(iterator from, iterator to) { std::sort(from, to, typename value_type::comparator_physical()); } /** * reorder this vector in-place, sorting by logical */ template void fr_vector::sort_by_logical() { std::sort(this->begin(), this->end(), typename value_type::comparator_logical()); } /** * reorder this vector in-place, sorting by logical */ template void fr_vector::sort_by_logical(iterator from, iterator to) { std::sort(from, to, typename value_type::comparator_logical()); } /** * reorder this vector in-place, sorting by reverse length (largest extents will be first) */ template void fr_vector::sort_by_reverse_length() { std::sort(this->begin(), this->end(), typename value_type::reverse_comparator_length()); } /** * reorder this vector in-place, sorting by reverse length (largest extents will be first) */ template void fr_vector::sort_by_reverse_length(iterator from, iterator to) { std::sort(from, to, typename value_type::reverse_comparator_length()); } /** * swap ->physical with ->logical in each extent of this vector. * Note: does NOT sort after swapping! */ template void fr_vector::transpose() { iterator iter = this->begin(), end_iter = this->end(); for (; iter != end_iter; ++iter) { value_type & e = *iter; std::swap(e.physical(), e.logical()); } } /** * used by ft_io_prealloc. * * truncate at specified logical value */ template void fr_vector::truncate_at_logical(T logical_end) { while (!this->empty()) { value_type & e = this->back(); T logical = e.logical(); if (logical >= logical_end) { this->pop_back(); continue; } T & length = e.length(); T delta = logical_end - logical; if (length > delta) length = delta; break; } } /** * used by ft_io_prealloc. * * given a vector mapping a<->c (v1, 'a' is stored in ->physical and 'c' in ->logical) * and a vector mapping b<->c (v2, 'a' is stored in ->physical and 'c' in ->logical), * compute the vector mapping a<->b (v2, 'a' is stored in ->physical and 'b' in ->logical) * and append it to this vector. * * user_data will be copied from v2. * all extents in b not mapped to c will be added to 'unmapped' (if unmapped is not NULL) * * Prerequisite: a<->c and b<->c must be sorted by ->logical (i.e. by 'c') * * Returns error if a<->c codomain (range in 'c') is smaller than b->c codomain (range in 'c') * and in particular if a<->c has holes in 'c' where b->c does not. */ template int fr_vector::compose0(const fr_vector & v1, const fr_vector & v2, T & ret_block_size_bitmask, fr_vector * unmapped) { T block_size_bitmask = ret_block_size_bitmask; ft_size n1 = v1.size(), n2 = v2.size(); int err = 0; if (n1 == 0) { if (n2 != 0) { ff_log(FC_ERROR, 0, "compose(): a<->c mapping is empty while b<->c mapping is not"); err = -EINVAL; } return err; } ft_size i1 = 0, i2 = 0; T delta1 = 0, delta2 = 0; while (i1 < n1 && i2 < n2) { const value_type & e1 = v1[i1], & e2 = v2[i2]; const T phys1 = e1.physical(), log1 = e1.logical(), len1 = e1.length(); const T phys2 = e2.physical(), log2 = e2.logical(), len2 = e2.length(); if (!ff_can_sum(phys1, len1) || !ff_can_sum(log1, len1)) { ff_log(FC_ERROR, 0, "compose(): a<->c extent {physical = %" FT_ULL ", logical = %" FT_ULL ", length = %" FT_ULL "} overflows type T", (ft_ull) phys1, (ft_ull) log1, (ft_ull) len1); err = -EFBIG; } else if (!ff_can_sum(phys2, len2) || !ff_can_sum(log2, len2)) { ff_log(FC_ERROR, 0, "compose(): b<->c extent {physical = %" FT_ULL ", logical = %" FT_ULL ", length = %" FT_ULL "} overflows type T", (ft_ull) phys2, (ft_ull) log2, (ft_ull) len2); err = -EFBIG; } else if (delta1 >= len1) { ff_log(FC_FATAL, 0, "compose(): internal error, length offset = %" FT_ULL " is not strictly inside a<->c extent" " {physical = %" FT_ULL ", logical = %" FT_ULL ", length = %" FT_ULL "}", (ft_ull) delta1, (ft_ull) log1, (ft_ull) phys1, (ft_ull) len1); err = -EINVAL; } else if (delta2 >= len2) { ff_log(FC_FATAL, 0, "compose(): internal error, length offset = %" FT_ULL " is not strictly inside b<->c extent" " {physical = %" FT_ULL ", length = %" FT_ULL "}", (ft_ull) delta2, (ft_ull) log2, (ft_ull) phys2, (ft_ull) len2); err = -EINVAL; } else if (log1 + delta1 < log2 + delta2) { ff_log(FC_ERROR, 0, "compose(): unexpected hole: a<->c mapping {physical = %" FT_ULL ", logical = %" FT_ULL ", length = %" FT_ULL "} with offset = %" FT_ULL , (ft_ull) phys1, (ft_ull) log1, (ft_ull) len1, (ft_ull) delta1); ff_log(FC_ERROR, 0, " cannot be covered by b<->c mapping {physical = %" FT_ULL ", logical = %" FT_ULL ", length = %" FT_ULL "} with offset = %" FT_ULL , (ft_ull) phys2, (ft_ull) log2, (ft_ull) len2, (ft_ull) delta2); err = -EINVAL; } if (err != 0) break; const ft_size user_data = e2.user_data(); if (log1 + delta1 > log2 + delta2) { // a<->c (v1) has a hole: insert the unmapped b<->c fragment in 'unmapped' T hole_len = ff_min2(len2 - delta2, (log1 + delta1) - (log2 + delta2)); if (unmapped != 0) { unmapped->append(phys2 + delta2, log2 + delta2, hole_len, user_data); } delta2 += hole_len; } const T len = ff_min2(len1 - delta1, len2 - delta2); if (len > 0) { append(phys1 + delta1, phys2 + delta2, len, user_data); block_size_bitmask |= (phys1 + delta1) | (phys2 + delta2) | len; } if (len != len1 - delta1) delta1 += len; else delta1 = 0, i1++; if (len != len2 - delta2) delta2 += len; else delta2 = 0, i2++; } if (err == 0) { const value_type & e1 = v1[i1 < n1 ? i1 : n1 - 1], & e2 = v2[i2 < n2 ? i2 : n2 - 1]; const T phys1 = e1.physical(), log1 = e1.logical(), len1 = e1.length(); const T phys2 = e2.physical(), log2 = e2.logical(), len2 = e2.length(); if (i1 < n1 && i2 == n2) { ff_log(FC_ERROR, 0, "compose() error: a<->c current extent {physical = %" FT_ULL ", logical = %" FT_ULL ", length = %" FT_ULL "}" " cannot be covered by b<->c last extent {physical = %" FT_ULL ", logical = %" FT_ULL ", length = %" FT_ULL "}", (ft_ull) phys1, (ft_ull) log1, (ft_ull) len1, (ft_ull) phys2, (ft_ull) log2, (ft_ull) len2); err = -EINVAL; } else if (i1 == n1 && i2 < n2) { // a<->c (v1) has a hole: insert the unmapped b<->c fragment in 'unmapped' if (unmapped != 0) { T hole_len = len2 - delta2; unmapped->append(phys2 + delta2, log2 + delta2, hole_len, e2.user_data()); } } } if (err == 0) ret_block_size_bitmask = block_size_bitmask; return err; } /** print vector contents to log */ template void fr_vector::show(const char * label1, const char * label2, ft_uoff effective_block_size, ft_log_level level) const { fr_extent::show(this->begin(), this->end(), this->size(), label1, label2, effective_block_size, level); } FT_NAMESPACE_END fstransform-0.9.4/fsremap/src/work.cc000066400000000000000000000022041345021500300175740ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * work.cc * * Created on: Feb 28, 2011 * Author: max */ #include "first.hh" // for FT_*TEMPLATE* macros */ #ifdef FT_HAVE_EXTERN_TEMPLATE # include "work.t.hh" FT_TEMPLATE_INSTANTIATE(FT_TEMPLATE_work_hh) #endif /* FT_HAVE_EXTERN_TEMPLATE */ fstransform-0.9.4/fsremap/src/work.hh000066400000000000000000000215241345021500300176140ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * remap.hh * * Created on: Feb 28, 2011 * Author: max */ #ifndef FSREMAP_WORK_HH #define FSREMAP_WORK_HH #include "types.hh" // for ft_uoff #include "map_stat.hh" // for fr_map_stat #include "eta.hh" // for ft_eta #include "log.hh" // for ft_log_level #include "io/io.hh" // for fr_io FT_NAMESPACE_BEGIN /** * class doing the core of remapping work. * * contains the algorithm to move LOOP-FILE around * until its physical layout matches its logical layout. * at that point, DEVICE will have been fully remaped. */ template class fr_work { private: typedef fr_map_stat map_stat_type; typedef fr_map map_type; typedef typename fr_map::iterator map_iterator; typedef typename fr_map::const_iterator map_const_iterator; typedef typename fr_map::key_type map_key_type; typedef typename fr_map::mapped_type map_mapped_type; typedef typename fr_map::value_type map_value_type; map_stat_type dev_map, storage_map; map_type dev_free, dev_transpose; map_type storage_free, storage_transpose; map_type toclear_map; FT_IO_NS fr_io * io; ft_eta eta; T work_total; /** cannot call copy constructor */ fr_work(const fr_work &); /** cannot call assignment operator */ const fr_work & operator=(const fr_work &); /** * call check(io) to ensure that io.dev_length() can be represented by T, * then checks that I/O is open. * if success, stores a reference to I/O object. */ int init(FT_IO_NS fr_io & io); /** * analysis phase of remapping algorithm, * must be executed before create_secondary_storage() and relocate() * * given LOOP-FILE extents and FREE-SPACE extents as ft_vectors, * compute LOOP-FILE extents map and DEVICE in-use extents map * and stores them into this->loop_map and this->dev_map. * * assumes that vectors are ordered by extent->logical, and modifies them * in place: vector contents will be UNDEFINED when this method returns. * * implementation: to compute this->dev_map, performs in-place the union of specified * loop_file_extents and free_space_extents, then sorts in-place and complements such union. */ int analyze(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents); /** * fill io->primary_storage() with DEVICE extents to be actually used as PRIMARY-STORAGE * (already computed into storage_map by analyze()) * * if only a fraction of available PRIMARY-STORAGE will be actually used, * exploit a fr_pool to select the largest contiguous extents. * * updates storage_map to contain the PRIMARY-STORAGE extents actually used. */ void fill_io_primary_storage_extents(ft_size primary_size); /** * creates on-disk secondary storage, used as (small) backup area during relocate(). * must be executed before relocate() */ int create_storage(); /** start UI, passing I/O object to it. requires I/O to know device length and storage size */ int start_ui(); /** core of remapping algorithm, actually moves DEVICE blocks */ int relocate(); /** * called by run() after relocate(). depending on job_clear, it will: * 1) if job_clear == FC_CLEAR_ALL, fill with zeroes all free space * 2) if job_clear == FC_CLEAR_MINIMAL, fill with zeroes PRIMARY-STORAGE, DEVICE-RENUMBERED and LOOP-FILE "unwritten" extents * 3) if job_clear == FC_CLEAR_NONE, only fill with zeroes LOOP-FILE "unwritten" extents */ int clear_free_space(); /** called after relocate() and clear_free_space(). closes storage */ int close_storage_after_success(); /** * called once by relocate() immediately before starting the remapping phase. * * 1) check that last device block to be written is actually writable. * Reason: at least on Linux, if a filesystems is smaller than its containing device, * it often limits to its length the writable blocks in the device. * * 2) check for corner care where we have an odd-sized (i.e. smaller than effective block size) last device block, * which does not appear in any extent map: its length is zero in 1-block units ! * * by itself it is not a problem and we could just ignore it, * but it is likely that an equally odd-sized (or slightly smaller) last loop-file block will be present, * and since its length is instead rounded UP to one block by the various io->read_extents() functions, * the normal algorithm in relocate() would not find its final destination and enter an infinite loop (ouch) */ int check_last_block(); /** called by relocate(). move as many extents as possible from DEVICE to STORAGE */ int fill_storage(); /** called by relocate(). move as many extents as possible from DEVICE or STORAGE directly to their final destination */ int move_to_target(fr_from from); /** * called by fill_storage(). * move as much as possible of a single extent from DEVICE to FREE-STORAGE or from STORAGE to FREE-DEVICE. * invalidates from_iter. * note: the extent can be fragmented in the process. * on return, 'ret_moved' will be increased by the number of blocks actually moved * note: some blocks may be moved even in case of errors! */ int move(ft_size counter, map_iterator from_iter, fr_dir dir, T & ret_moved); /** * called by move(). * move a single fragment from DEVICE to FREE STORAGE, or from STORAGE to FREE-DEVICE or from DEVICE to FREE DEVICE. * the moved amount is the largest between (from_length = from_iter->length) and (to_length = to_free_iter->length). * * updates dev_* and storage_* maps. * * if from_length <= to_length, invalidates from_iter. * if from_length >= to_length, invalidates to_iter. * * on return, 'ret_moved' will be increased by the number of blocks actually moved * note: some blocks may be moved even in case of errors! */ int move_fragment(map_iterator from_iter, map_iterator to_free_iter, fr_dir dir, T & ret_moved); /** read or write next step from persistence file */ int update_persistence(); /** show progress status and E.T.A. */ void show_progress(ft_log_level log_level); public: /** default constructor */ fr_work(); /** destructor. calls cleanup() */ ~fr_work(); /** * high-level do-everything method. calls in sequence run() and cleanup(). * return 0 if success, else error. */ static int main(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents, FT_IO_NS fr_io & io); /** * check if LOOP-FILE and DEVICE in-use extents can be represented * by fr_map. takes into account the fact that all extents * physical, logical and length will be divided by effective block size * before storing them into fr_map. * * return 0 for check passes, else error (usually EFBIG) */ static int check(const FT_IO_NS fr_io & io); /** * main remapping algorithm. * calls in sequence init(), analyze(), create_secondary_storage() and relocate() */ int run(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents, FT_IO_NS fr_io & io); /** performs cleanup. called by destructor, you can also call it explicitly after (or instead of) run() */ void cleanup(); }; FT_NAMESPACE_END #ifdef FT_HAVE_EXTERN_TEMPLATE # define FT_TEMPLATE_work_hh(ft_prefix, T) ft_prefix class FT_NS fr_work< T >; FT_TEMPLATE_DECLARE(FT_TEMPLATE_work_hh) #else # include "work.t.hh" #endif /* FT_HAVE_EXTERN_TEMPLATE */ #endif /* FSREMAP_WORK_HH */ fstransform-0.9.4/fsremap/src/work.t.hh000066400000000000000000001617031345021500300200620ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * work.t.hh * * Created on: Feb 28, 2011 * Author: max */ #include "first.hh" #if defined(FT_HAVE_ERRNO_H) # include // for errno, EOVERFLOW #elif defined(FT_HAVE_CERRNO) # include // for errno, EOVERFLOW #endif #if defined(FT_HAVE_STRING_H) # include // for strerror() #elif defined(FT_HAVE_CSTRING) # include // for strerror() #endif #include "assert.hh" // for ff_assert() #include "log.hh" // for ff_log() #include "vector.hh" // for fr_vector #include "map.hh" // for fr_map #include "pool.hh" // for fr_pool #include "misc.hh" // for ff_pretty_size() #include "work.hh" // for ff_dispatch(), fr_work #include "arch/mem.hh" // for ff_arch_mem_system_free() #include "io/io.hh" // for fr_io #include "io/io_posix.hh" // for fr_io_posix #include "ui/ui.hh" // for fr_ui FT_NAMESPACE_BEGIN enum { FC_DEVICE = FT_IO_NS fr_io::FC_DEVICE, FC_LOOP_FILE = FT_IO_NS fr_io::FC_LOOP_FILE, FC_FREE_SPACE = FT_IO_NS fr_io_posix::FC_FREE_SPACE, FC_STORAGE = FT_IO_NS fr_io_posix::FC_STORAGE, FC_PRIMARY_STORAGE = FT_IO_NS fr_io_posix::FC_PRIMARY_STORAGE, FC_SECONDARY_STORAGE = FT_IO_NS fr_io_posix::FC_SECONDARY_STORAGE, }; char const* const* const label = FT_IO_NS fr_io_posix::label; char const* const label_LOOP_HOLES = "loop-holes"; /** default constructor */ template fr_work::fr_work() : dev_map(), storage_map(), dev_free(), dev_transpose(), storage_free(), storage_transpose(), toclear_map(), io(NULL), eta(), work_total(0) { } #ifdef FT_HAVE_EXTERNAL_TEMPLATE /** * copy constructor CANNOT be invoked, * but some C++ compilers need it to be defined * if explicit template instantiation is used */ template fr_work::fr_work(const fr_work & other) { ff_assert_fail("fr_work copy constructor CANNOT be invoked"); } /** assignment operator CANNOT be invoked */ template const fr_work & fr_work::operator=(const fr_work & other) { ff_assert_fail("fr_work assignment operator CANNOT be invoked"); } #endif /* FT_HAVE_EXTERNAL_TEMPLATE */ /** destructor. calls cleanup() */ template fr_work::~fr_work() { cleanup(); } /** performs cleanup. called by destructor, you can also call it explicitly after (or instead of) run() */ template void fr_work::cleanup() { dev_map.clear(); storage_map.clear(); dev_free.clear(); dev_transpose.clear(); storage_free.clear(); storage_transpose.clear(); toclear_map.clear(); eta.clear(); work_total = 0; } /** * high-level do-everything method. calls in sequence init(), run() and cleanup(). * return 0 if success, else error. */ template int fr_work::main(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents, FT_IO_NS fr_io & io) { fr_work worker; return worker.run(loop_file_extents, free_space_extents, to_zero_extents, io); // worker.cleanup() is called automatically by destructor, no need to call explicitly } /** full remapping algorithm */ template int fr_work::run(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents, FT_IO_NS fr_io & io) { int err; if ((err = init(io)) == 0 && (err = analyze(loop_file_extents, free_space_extents, to_zero_extents)) == 0 && (err = create_storage()) == 0 && (err = start_ui()) == 0 && (err = relocate()) == 0 && (err = clear_free_space()) == 0 && (err = close_storage_after_success()) == 0) { } if (err == 0) { ff_log(FC_NOTICE, 0, "%sjob completed.", io.simulate_run() ? "(simulated) " : ""); } else if (!ff_log_is_reported(err)) { /* * note 1.2.2) fr_remap.main() and other high-level *.main() methods * must check for unreported errors and log them them with message * "failed with unreported error" */ err = ff_log(FC_ERROR, err, "failed with unreported error"); } return err; } /** * check if LOOP-FILE and DEVICE in-use extents can be represented * by fr_map. takes into account the fact that all extents * physical, logical and length will be divided by effective block size * before storing them into fr_map. * * return 0 for check passes, else error (usually EOVERFLOW) */ template int fr_work::check(const FT_IO_NS fr_io & io) { ft_uoff eff_block_size_log2 = io.effective_block_size_log2(); ft_uoff dev_length = io.dev_length(); ft_uoff block_count = dev_length >> eff_block_size_log2; // possibly narrowing cast, let's check for overflow T n = (T) block_count; int err = 0; if (n < 0 || block_count != (ft_uoff) n) /* overflow! */ err = EOVERFLOW; return err; } /** * call check(io) to ensure that io.dev_length() can be represented by T, * then checks that I/O is open. * if success, stores a reference to I/O object. */ template int fr_work::init(FT_IO_NS fr_io & io) { int err; do { if ((err = check(io)) != 0) break; if (!io.is_open()) { err = ENOTCONN; // I/O is not open ! break; } this->io = & io; } while (0); return err; } static ft_size ff_mem_page_size() { enum { FC_PAGE_SIZE_IF_UNKNOWN = 4096 // assume 4k (most common value) if cannot be detected }; static ft_size page_size = 0; if (page_size == 0) { if ((page_size = FT_ARCH_NS ff_arch_mem_page_size()) == 0) { ff_log(FC_WARN, 0, "cannot detect system PAGE_SIZE. assuming 4 kilobytes and continuing, but troubles (mmap() errors) are very likely"); page_size = FC_PAGE_SIZE_IF_UNKNOWN; } } return page_size; } template static T ff_round_up(T n, T power_of_2_minus_1) { if (n & power_of_2_minus_1) n = (n | power_of_2_minus_1) + 1; return n; } /* trim extent on both ends to align it to page_size. return trimmed extent length (can be zero) */ template T ff_extent_align(typename fr_map::value_type & extent, T page_size_blocks_m_1) { T physical = extent.first.physical; T end = physical + extent.second.length; T new_physical = ff_round_up(physical, page_size_blocks_m_1); T new_end = end & ~page_size_blocks_m_1; if (new_end <= new_physical) return extent.second.length = 0; extent.first.physical = new_physical; extent.second.logical += new_physical - physical; return extent.second.length = new_end - new_physical; } /** * analysis phase of remapping algorithm, * must be executed before create_storage() and relocate() * * given LOOP-FILE extents and FREE-SPACE extents as ft_vectors, * compute LOOP-FILE extents map and DEVICE in-use extents map * * assumes that vectors are ordered by extent->logical, and modifies them * in place: vector contents will be UNDEFINED when this method returns. * * basic implementation idea: to compute this->dev_map, performs in-place the union of specified * loop_file_extents and free_space_extents, then sorts in-place and complements such union. * * detailed implementation is quite complicated... see the comments and the documentation */ template int fr_work::analyze(fr_vector & loop_file_extents, fr_vector & free_space_extents, fr_vector & to_zero_extents) { // cleanup in case dev_map, storage_map or storage_map are not empty, or work_count != 0 cleanup(); map_type loop_map, loop_holes_map, renumbered_map; ft_uoff eff_block_size_log2 = io->effective_block_size_log2(); ft_uoff eff_block_size = (ft_uoff)1 << eff_block_size_log2; ft_uoff dev_length = io->dev_length(); /* * algorithm: 1) find LOOP-FILE (logical) holes, i.e. LOOP-HOLES, * and store them in loop_holes_map * note: all complement maps have physical == logical */ loop_holes_map.complement0_logical_shift(loop_file_extents, eff_block_size_log2, dev_length); if (io->job_clear() == FC_CLEAR_ALL) toclear_map = loop_holes_map; // merge to_zero_extents into toclear_map toclear_map.merge_shift(to_zero_extents, eff_block_size_log2, FC_PHYSICAL1); /* algorithm: 0) compute LOOP-FILE extents and store in loop_map, sorted by physical */ loop_file_extents.sort_by_physical(); loop_map.append0_shift(loop_file_extents, eff_block_size_log2); /* show LOOP-FILE extents sorted by physical */ loop_map.show(label[FC_LOOP_FILE], "", eff_block_size); /* algorithm: 0) compute FREE-SPACE extents and store in dev_free, sorted by physical * * we must manually set ->logical = ->physical for all free_space_extents: * here dev_free is just free space, but for I/O that computed it * it could have been a ZERO-FILE with its own ->logical, * * note: changing ->logical may also allow merging extents! */ { fr_vector::const_iterator iter = free_space_extents.begin(), end = free_space_extents.end(); T physical, length; for (; iter != end; ++iter) { physical = iter->first.physical >> eff_block_size_log2; length = iter->second.length >> eff_block_size_log2; dev_free.insert(physical, physical, length, FC_DEFAULT_USER_DATA); } } /* sanity check: LOOP-FILE and FREE-SPACE extents ->physical must NOT intersect */ renumbered_map.intersect_all_all(loop_map, dev_free, FC_PHYSICAL1); if (!renumbered_map.empty()) { ff_log(FC_FATAL, 0, "inconsistent %s and %s: they share common blocks on %s !", label[FC_LOOP_FILE], label[FC_FREE_SPACE], label[FC_DEVICE]); renumbered_map.show(label[FC_LOOP_FILE], " intersection with free-space", eff_block_size, FC_DEBUG); return -EFAULT; } /* * move from LOOP-FILE to DEV-FREE and to TO-CLEAR-MAP * the (physical) extents in LOOP-FILE that are full with zeros (UNWRITTEN). * * this converts FC_EXTENT_ZEROED extents into free extents, * and will also mark them to be cleared after relocate() finishes. */ map_iterator iter = loop_map.begin(), tmp, end = loop_map.end(); { T physical, length; while (iter != end) { map_value_type & extent = *iter; if (extent.second.user_data == FC_EXTENT_ZEROED) { physical = extent.first.physical; length = extent.second.length; /* extent must be inserted in toclear_map even if io->job_clear() == FC_CLEAR_ALL */ toclear_map.insert(physical, physical, length, FC_DEFAULT_USER_DATA); dev_free.insert(physical, physical, length, FC_DEFAULT_USER_DATA); tmp = iter; ++iter; loop_map.remove(tmp); } else ++iter; } } toclear_map.show("to-clear", " (initial)", eff_block_size, FC_DEBUG); dev_free.show(label[FC_FREE_SPACE], " (after to-clear)", eff_block_size); /* algorithm: 0) compute DEVICE extents * * how: compute physical complement of all LOOP-FILE and FREE-SPACE extents * and assume they are used by DEVICE for its file-system */ /* compute in-place the union of LOOP-FILE extents and FREE-SPACE extents */ loop_file_extents.append_all(free_space_extents); /* sort the union by physical: needed by dev_map.complement0_physical_shift() immediately below */ loop_file_extents.sort_by_physical(); dev_map.complement0_physical_shift(loop_file_extents, eff_block_size_log2, dev_length); /* show DEVICE extents sorted by physical */ dev_map.show(label[FC_DEVICE], "", eff_block_size); /* * algorithm: 2), 3) allocate LOOP-HOLES for DEVICE extents logical destination * and for LOOP-FILE invariant extents */ /* show LOOP-HOLES extents before allocation, sorted by physical */ loop_holes_map.show(label_LOOP_HOLES, " (initial)", eff_block_size); /* algorithm: 2) re-number used DEVICE blocks, setting ->logical to values * from LOOP-HOLES. do not greedily use low hole numbers: * a) prefer holes with ->logical numbers equal to DEVICE ->physical block number: * they produce an INVARIANT block, already in its final destination * (marked with @@) * b) spread the remaining ->logical across rest of holes (use best-fit allocation) */ /* how: intersect dev_map and loop_holes_map and put result into renumbered_map */ renumbered_map.intersect_all_all(dev_map, loop_holes_map, FC_BOTH); /* show DEVICE INVARIANT extents (i.e. already in their final destination), sorted by physical */ renumbered_map.show(label[FC_DEVICE], " (invariant)", eff_block_size); /* remove from dev_map all the INVARIANT extents in renumbered_map */ dev_map.remove_all(renumbered_map); /* * also remove from loop_holes_map all extents in renumbered_map * reason: they are no longer free (logical) holes, * since we allocated them for DEVICE INVARIANT extents */ loop_holes_map.remove_all(renumbered_map); /* * then clear renumbered_map: its extents are already in their final destination * (they are INVARIANT) -> no work on them */ renumbered_map.clear(); /* show LOOP-HOLES (sorted by physical) after allocating DEVICE-INVARIANT extents */ loop_holes_map.show(label_LOOP_HOLES, " after device (invariant)", eff_block_size); /* * algorithm: 2) b) spread the remaining DEVICE ->logical across rest of LOOP-HOLES * (use best-fit allocation) */ /* order loop_holes_map by length */ fr_pool loop_holes_pool(loop_holes_map); /* * allocate LOOP-HOLES extents to store DEVICE extents using a best-fit strategy. * move allocated extents from dev_map to renumbered_map */ loop_holes_pool.allocate_all(dev_map, renumbered_map); /* show DEVICE RENUMBERED extents sorted by physical */ renumbered_map.show(label[FC_DEVICE], " (renumbered)", eff_block_size); /* show LOOP-HOLES extents after allocation, sorted by physical */ loop_holes_map.show(label_LOOP_HOLES, " (final)", eff_block_size); /* sanity check */ if (!dev_map.empty()) { ff_log(FC_FATAL, 0, "internal error: there are extents in DEVICE not fitting DEVICE. this is impossible! I give up"); /* show DEVICE-NOTFITTING extents sorted by physical */ dev_map.show(label[FC_DEVICE], " (not fitting)", eff_block_size, FC_NOTICE); return ENOSPC; } /* move DEVICE (RENUMBERED) back into dev_map and clear renumbered_map */ dev_map.swap(renumbered_map); if (io->job_clear() == FC_CLEAR_MINIMAL) { /* * also add DEVICE (RENUMBERED) to TO-CLEAR-MAP: * we MUST clear it once remapping is finished, * since it contains data from the original device, NOT from the loop-file * WARNING: beware of intersections, * and be careful to use dev_map->logical instead of dev_map->physical! */ dev_transpose.transpose(dev_map); renumbered_map.clear(); renumbered_map.intersect_all_all(dev_transpose, toclear_map, FC_PHYSICAL2); toclear_map.remove_all(renumbered_map); iter = dev_transpose.begin(); end = dev_transpose.end(); for (; iter != end; ++iter) { const map_value_type & extent = *iter; toclear_map.insert(extent.first.physical, extent.first.physical, extent.second.length, FC_DEFAULT_USER_DATA); } dev_transpose.clear(); toclear_map.show("to-clear", " (final)", eff_block_size, FC_DEBUG); } /* * 2.1) mark as INVARIANT (with @@) the (logical) extents in LOOP-FILE * already in their final destination, and forget them (no work on those). * also compute total length of extents remaining in LOOP-FILE and store in work_count. */ iter = loop_map.begin(); end = loop_map.end(); T work_count = 0; /**< number of blocks to be relocated */ while (iter != end) { if (iter->first.physical == iter->second.logical) { /* move INVARIANT extents to renumbered_map, to show them later */ renumbered_map.insert(*iter); tmp = iter; ++iter; /* forget INVARIANT extents (i.e. remove from loop_map) */ loop_map.remove(tmp); } else { /* not INVARIANT, compute loop_map length... */ work_count += iter->second.length; /* * also prepare for item 3) "merge renumbered DEVICE extents with remaining LOOP-FILE extents" * i.e. remember who's who */ iter->second.user_data = FC_LOOP_FILE; ++iter; } } /* show LOOP-FILE (INVARIANT) blocks, sorted by physical */ renumbered_map.show(label[FC_LOOP_FILE], " (invariant)", eff_block_size); /* then forget them */ renumbered_map.clear(); /* * algorithm: 3) merge renumbered DEVICE extents with LOOP-FILE blocks (remember who's who) * also compute total length of extents remaining in DEVICE and add it to work_count. */ iter = dev_map.begin(); end = dev_map.end(); for (; iter != end; ++iter) { work_count += iter->second.length; iter->second.user_data = FC_DEVICE; loop_map.insert0(iter->first, iter->second); } dev_map.clear(); /* * from now on, we only need one of dev_map or loop_map, not both. * we choose dev_map: more intuitive name, and already stored in 'this' */ dev_map.swap(loop_map); dev_map.total_count(work_count); dev_map.used_count(work_count); /* show DEVICE + LOOP-FILE extents after merge, sorted by physical */ dev_map.show("device + loop-file", " (merged)", eff_block_size); double pretty_len = 0.0; const char * pretty_unit = ff_pretty_size((ft_uoff) work_count << eff_block_size_log2, & pretty_len); ff_log(FC_NOTICE, 0, "analysis completed: %.2f %sbytes must be relocated", pretty_len, pretty_unit); /* * algorithm: 4) compute (physical) intersection of FREE-SPACE and LOOP-HOLES, * and mark it as FREE-SPACE (INVARIANT) (with !!). * we can use these extents as partial or total replacement for STORAGE - see 5) * if they are relatively large (see below for meaning of "relatively large") * * forget the rest of LOOP-HOLES extents, we will not need them anymore */ /* * how: intersect storage_map (hosted in dev_free variable) * and loop_holes_map and put result into renumbered_map */ renumbered_map.clear(); renumbered_map.intersect_all_all(dev_free, loop_holes_map, FC_BOTH); /* then discard extents smaller than either work_count / 1024 or page_size*/ /* page_size_blocks = number of blocks in one RAM page. will be zero if page_size < block_size */ const ft_size page_size = ff_mem_page_size(); const T page_size_blocks = (T) (page_size >> eff_block_size_log2); /* * consider for PRIMARY-STORAGE only "relatively large" blocks, i.e. * 1) at least 1024 * PAGE_SIZE bytes long, or at least work_count / 1024 blocks long * 2) in any case, at least 1 * PAGE_SIZE bytes long */ ft_uoff hole_threshold = ff_max2((ft_uoff)page_size_blocks, ff_min2((ft_uoff) work_count >> 10, (ft_uoff) page_size << 10 >> eff_block_size_log2)); T hole_len, hole_total_len = 0; iter = renumbered_map.begin(); end = renumbered_map.end(); renumbered_map.show(label[FC_FREE_SPACE], " (invariant)", eff_block_size); while (iter != end) { map_value_type & extent = *iter; /* * whether this hole (extent from dev_free) is large enough to be useful or not, * it is invariant free space. the current remapping algorithm will never use it, * so remove it from free space to get accurate calculation of usable free space. */ dev_free.remove(extent); if ((ft_uoff) (hole_len = iter->second.length) >= hole_threshold) { /* trim hole on both ends to align it to PAGE_SIZE */ if (page_size_blocks <= 1 || (ft_uoff) (hole_len = ff_extent_align(extent, page_size_blocks - 1)) >= hole_threshold) { hole_total_len += hole_len; ++iter; continue; } } /* extent is small, do not use for PRIMARY-STORAGE */ tmp = iter; ++iter; renumbered_map.remove(tmp); } /* * move FREE-SPACE (INVARIANT) extents into storage_map (i.e. PRIMARY-STORAGE), * as the latter is stored into 'this' */ storage_map.swap(renumbered_map); /* show PRIMARY-STORAGE extents, sorted by physical */ storage_map.show(label[FC_PRIMARY_STORAGE], " (= free-space, invariant, contiguous, aligned)", eff_block_size); pretty_len = 0.0; pretty_unit = ff_pretty_size((ft_uoff) hole_total_len << eff_block_size_log2, & pretty_len); ft_size storage_map_n = storage_map.size(); ff_log(FC_INFO, 0, "%s: located %.2f %sbytes (%" FT_ULL " fragment%s) usable in %s (free, invariant, contiguous and aligned)", label[FC_PRIMARY_STORAGE], pretty_len, pretty_unit, (ft_ull)storage_map_n, (storage_map_n == 1 ? "" : "s"), label[FC_DEVICE]); storage_map.total_count(hole_total_len); /* all done */ return 0; } static int unusable_storage_size(const char * label, ft_uoff requested_len, const char * type_descr, ft_ull type_bytes) { ff_log(FC_FATAL, 0, "fatal error: cannot use job %s length = %" FT_ULL " bytes, it is incompatible with %s = %" FT_ULL " bytes," " original job was probably created on a platform with %s", label, (ft_ull) requested_len, type_descr, type_bytes); /* mark error as reported */ return -EOVERFLOW; } /** * creates on-disk secondary storage, used as (hopefully small) backup area during relocate(). * must be executed before relocate() */ template int fr_work::create_storage() { enum { _1M_minus_1 = 1024*1024 - 1, _64k_minus_1 = 64*1024 - 1, }; const ft_uoff eff_block_size_log2 = io->effective_block_size_log2(); const ft_uoff eff_block_size_minus_1 = ((ft_uoff)1 << eff_block_size_log2) - 1; const ft_uoff free_ram_or_0 = FT_ARCH_NS ff_arch_mem_system_free(); const ft_uoff free_ram_or_min = free_ram_or_0 != 0 ? free_ram_or_0 : sizeof(ft_size) <= 4 ? (ft_uoff) 48*1024*1024 : (ft_uoff) 768*1024*1024; ft_uoff avail_primary_len = (ft_uoff) storage_map.total_count() << eff_block_size_log2; ft_size avail_primary_size = (ft_size) ff_min2(avail_primary_len, (ft_size)-1); ft_size auto_total_size = 0, mem_buffer_size; const ft_size page_size_minus_1 = ff_mem_page_size() - 1; ft_size req_mem_buffer_size = io->job_storage_size(FC_MEM_BUFFER_SIZE); ft_size req_secondary_size = io->job_storage_size(FC_SECONDARY_STORAGE_SIZE); ft_size tmp_primary_size_exact = 0, tmp_secondary_size_exact = 0; FT_IO_NS fr_persist & persist = io->persist(); bool persist_has_sizes_exact = persist.is_replaying(); { int err = persist.get_storage_sizes_exact(tmp_primary_size_exact, tmp_secondary_size_exact); if (err != 0) return err; } const ft_size req_primary_size_exact = tmp_primary_size_exact; const ft_size req_secondary_size_exact = tmp_secondary_size_exact; const ft_size req_total_size_exact = req_primary_size_exact + req_secondary_size_exact; double free_pretty_len = 0.0; const char * free_pretty_unit = ff_pretty_size(free_ram_or_min, & free_pretty_len); if (req_primary_size_exact != 0 && req_secondary_size_exact != 0 && req_secondary_size_exact > (ft_size)-1 - req_primary_size_exact) { double req_p_pretty_len = 0.0, req_s_pretty_len = 0.0; const char * req_p_pretty_unit = ff_pretty_size(req_primary_size_exact, & req_p_pretty_len); const char * req_s_pretty_unit = ff_pretty_size(req_secondary_size_exact, & req_s_pretty_len); return ff_log(FC_ERROR, EOVERFLOW, "requested %s + %s exact size (%.2f %sbytes + %.2f %sbytes) overflow addressable memory", label[FC_PRIMARY_STORAGE], label[FC_SECONDARY_STORAGE], req_p_pretty_len, req_p_pretty_unit, req_s_pretty_len, req_s_pretty_unit); } if (free_ram_or_0 == 0) ff_log(FC_WARN, 0, "cannot detect free RAM amount"); if (req_total_size_exact != 0 || req_secondary_size != 0) { /* honor requested storage size, but warn if it may exhaust free RAM */ const ft_size req_len = req_total_size_exact != 0 ? req_total_size_exact : req_secondary_size; const char * req_label = label[req_total_size_exact != 0 ? FC_STORAGE : FC_SECONDARY_STORAGE]; double req_pretty_len = 0.0; const char * req_pretty_unit = ff_pretty_size(req_len, & req_pretty_len); if (free_ram_or_0 == 0) { ff_log(FC_WARN, 0, "no idea if the %.2f %sbytes requested for %s%s will fit into free RAM", req_pretty_len, req_pretty_unit, "mmapped() ", req_label); ff_log(FC_WARN, 0, "continuing, but troubles (memory exhaustion) are possible"); } else if ((ft_uoff) req_len >= free_ram_or_0 / 2) { ff_log(FC_WARN, 0, "using %.2f %sbytes as requested for %s%s, but only %.2f %sbytes RAM are free", req_pretty_len, req_pretty_unit, "mmapped() ", req_label, free_pretty_len, free_pretty_unit); ff_log(FC_WARN, 0, "honoring the request, but expect troubles (memory exhaustion)"); } } if (req_total_size_exact == 0) { /* * auto-detect total storage size to use: * we want it to be the smallest between * 50% of free RAM (if free RAM cannot be determined, use 16 MB on 32bit platforms, and 256MB on 64bit+ platforms) * 12.5% of bytes to relocate */ if (req_secondary_size == 0 && free_ram_or_0 == 0) { ff_log(FC_WARN, 0, "assuming at least %.2f %sbytes RAM are free", free_pretty_len, free_pretty_unit); ff_log(FC_WARN, 0, "expect troubles (memory exhaustion) if not true"); } T work_count = dev_map.used_count(); ft_uoff work_length_8 = (((ft_uoff) work_count << eff_block_size_log2) + 7) / 8; ft_uoff total_len = ff_min2(free_ram_or_min / 2, work_length_8); /* round up to multiples of 1M */ total_len = ff_round_up(total_len, _1M_minus_1); /* truncate to ft_size */ auto_total_size = (ft_size) ff_min2(total_len, (ft_uoff)(ft_size)-1); } if (req_mem_buffer_size != 0) { const ft_size req_len = req_mem_buffer_size; double req_pretty_len = 0.0; const char * req_pretty_unit = ff_pretty_size(req_len, & req_pretty_len); if (free_ram_or_0 == 0) { ff_log(FC_WARN, 0, "no idea if the %.2f %sbytes requested for %s%s will fit into free RAM", req_pretty_len, req_pretty_unit, "memory ", "buffer"); ff_log(FC_WARN, 0, "continuing, but troubles (memory exhaustion) are possible"); } else if ((ft_uoff) req_len >= free_ram_or_0 / 2) { ff_log(FC_WARN, 0, "using %.2f %sbytes as requested for %s%s, but only %.2f %sbytes RAM are free", req_pretty_len, req_pretty_unit, "memory ", "buffer", free_pretty_len, free_pretty_unit); ff_log(FC_WARN, 0, "honoring the request, but expect troubles (memory exhaustion)"); } mem_buffer_size = req_mem_buffer_size; } else { /* * autodect RAM buffer size: * it will be the smallest between 25% free RAM and number of bytes to relocate * (and truncated to fit addressable RAM) */ ft_uoff work_bytes = (ft_uoff)dev_map.used_count() << eff_block_size_log2; mem_buffer_size = (ft_size) ff_min2((ft_uoff)(ft_size)-1, ff_min2(free_ram_or_min / 4, work_bytes)); } bool flag; /* round down all parameters to a multiple of PAGE_SIZE */ mem_buffer_size &= ~page_size_minus_1; auto_total_size &= ~page_size_minus_1; avail_primary_size &= ~page_size_minus_1; req_secondary_size &= ~page_size_minus_1; if ((flag = ((req_primary_size_exact & page_size_minus_1) != 0)) || (req_secondary_size_exact & page_size_minus_1)) return unusable_storage_size(label[flag ? FC_PRIMARY_STORAGE : FC_SECONDARY_STORAGE], flag ? req_primary_size_exact : req_secondary_size_exact, "system PAGE_SIZE", (ft_ull)(page_size_minus_1 + 1)); /* round down all parameters to a multiple of effective block size */ mem_buffer_size &= ~eff_block_size_minus_1; auto_total_size &= ~eff_block_size_minus_1; avail_primary_size &= ~eff_block_size_minus_1; req_secondary_size &= ~eff_block_size_minus_1; if ((flag = ((req_primary_size_exact & eff_block_size_minus_1) != 0)) || (req_secondary_size_exact & eff_block_size_minus_1)) return unusable_storage_size(label[flag ? FC_PRIMARY_STORAGE : FC_SECONDARY_STORAGE], flag ? req_primary_size_exact : req_secondary_size_exact, "device effective block size", (ft_ull)(eff_block_size_minus_1 + 1)); /* * truncate mem_buffer_size to 1/4 of addressable RAM (= 1GB on 32-bit machines) * truncate all non-mandatory storage sizes (auto_total_size, avail_primary_size, req_secondary_size) * to 1/2 of addressable RAM (= 2GB on 32-bit machines) * keep alignment to PAGE_SIZE and effective block size! */ const ft_size mem_4 = (((ft_size)-1 >> 2) + 1) & ~page_size_minus_1 & ~eff_block_size_minus_1; const ft_size mem_2 = mem_4 << 1; mem_buffer_size = ff_min2(mem_buffer_size, mem_4); auto_total_size = ff_min2(auto_total_size, mem_2); avail_primary_size = ff_min2(avail_primary_size, mem_2); req_secondary_size = ff_min2(req_secondary_size, mem_2); if (req_total_size_exact == 0 && req_secondary_size == 0 && auto_total_size == 0) { auto_total_size = (page_size_minus_1 | eff_block_size_minus_1) + 1; double total_pretty_len = 0.0; const char * total_pretty_unit = ff_pretty_size(auto_total_size, & total_pretty_len); ff_log(FC_WARN, 0, "%s size to use would be 0 bytes, increasing to %.2f %sbytes", label[FC_STORAGE], total_pretty_len, total_pretty_unit); } if (mem_buffer_size == 0) { mem_buffer_size = (page_size_minus_1 | eff_block_size_minus_1) + 1; double mem_pretty_len = 0.0; const char * mem_pretty_unit = ff_pretty_size(mem_buffer_size, & mem_pretty_len); ff_log(FC_WARN, 0, "%s size to use would be 0 bytes, increasing to %.2f %sbytes", "memory buffer", mem_pretty_len, mem_pretty_unit); } ft_size primary_size; if (req_primary_size_exact > avail_primary_size) { double avail_pretty_len = 0.0, req_pretty_len = 0.0; const char * avail_pretty_unit = ff_pretty_size(avail_primary_size, & avail_pretty_len); const char * req_pretty_unit = ff_pretty_size(req_primary_size_exact, & req_pretty_len); ff_log(FC_ERROR, 0, "available %s is only %" FT_ULL " bytes (%.2f %sbytes)," " too small for requested %" FT_ULL " bytes (%.2f %sbytes)", label[FC_PRIMARY_STORAGE], (ft_ull)avail_primary_size, avail_pretty_len, avail_pretty_unit, (ft_ull) req_primary_size_exact, req_pretty_len, req_pretty_unit); /* mark error as reported */ return -ENOSPC; } else if (req_primary_size_exact != 0) primary_size = req_primary_size_exact; else primary_size = ff_min2(avail_primary_size, auto_total_size); ft_size secondary_size; if (req_secondary_size_exact != 0) secondary_size = req_secondary_size_exact; else if (req_secondary_size != 0) secondary_size = req_secondary_size; else if (auto_total_size > primary_size) secondary_size = auto_total_size - primary_size; else secondary_size = 0; /* remember storage sizes */ io->job_storage_size(FC_MEM_BUFFER_SIZE, mem_buffer_size); io->job_storage_size(FC_PRIMARY_STORAGE_EXACT_SIZE, primary_size); io->job_storage_size(FC_SECONDARY_STORAGE_EXACT_SIZE, secondary_size); /* * also save exact primary/secondary storage exact sizes to persistence, * in case this jobs gets interrupted and somebody else will try to resume it later. * * mem_buffer_size is not saved because it does not influence the remapping algorithm. */ if (!persist_has_sizes_exact) { int err = persist.set_storage_sizes_exact(primary_size, secondary_size); if (err != 0) return err; } /* fill io->primary_storage() with PRIMARY-STORAGE extents actually used */ fill_io_primary_storage_extents(primary_size); return io->create_storage(secondary_size, mem_buffer_size); } /** * fill io->primary_storage() with DEVICE extents to be actually used as PRIMARY-STORAGE * (already computed into storage_map by analyze()). * * if only a fraction of available PRIMARY-STORAGE will be actually used, * exploit a fr_pool to select the largest contiguous extents. * * updates storage_map to contain the PRIMARY-STORAGE extents actually used. */ template void fr_work::fill_io_primary_storage_extents(ft_size primary_size) { const ft_uoff primary_len = (ft_uoff) primary_size; const ft_uoff eff_block_size_log2 = io->effective_block_size_log2(); const ft_uoff eff_block_size_minus_1 = ((ft_uoff)1 << eff_block_size_log2) - 1; ff_assert((primary_len & eff_block_size_minus_1) == 0); /* first, copy all extents from storage_map to primary_storage */ fr_vector & primary_storage = io->primary_storage(); ft_uoff physical, length; map_iterator map_iter = storage_map.begin(), map_end = storage_map.end(); for (; map_iter != map_end; ++map_iter) { typename fr_map::value_type & extent = *map_iter; physical = (ft_uoff) extent.first.physical << eff_block_size_log2; length = (ft_uoff) extent.second.length << eff_block_size_log2; primary_storage.append(physical, physical, length, extent.second.user_data); } /* then check: if not all extents will be actually used, drop the smallest ones */ const ft_uoff available_len = (ft_uoff) storage_map.total_count() << eff_block_size_log2; if (available_len > primary_len) { ft_uoff extra_len = available_len - primary_len; /* sort by reverse length */ primary_storage.sort_by_reverse_length(); /* * iterate dropping the last (smallest) extents until we exactly reach primary_len. * (one final extent may be shrank instead of dropped) */ while (extra_len != 0 && !primary_storage.empty()) { fr_extent & extent = primary_storage.back(); length = extent.length(); if (length <= extra_len) { // completely drop this extent extra_len -= length; primary_storage.pop_back(); } else { // shrink this extent and break extent.length() -= extra_len; extra_len = 0; } } primary_storage.sort_by_physical(); /* update storage_map. needed by show() below */ storage_map.clear(); storage_map.append0_shift(primary_storage, eff_block_size_log2); } storage_map.total_count((T)(primary_len >> eff_block_size_log2)); double pretty_len = 0.0; const char * pretty_unit = ff_pretty_size(primary_len, & pretty_len); ft_size fragment_n = primary_storage.size(); ff_log(FC_INFO, 0, "%s: actually using %.2f %sbytes (%" FT_ULL " fragment%s) from %s", label[FC_PRIMARY_STORAGE], pretty_len, pretty_unit, (ft_ull)fragment_n, (fragment_n == 1 ? "" : "s"), label[FC_DEVICE]); storage_map.show(label[FC_PRIMARY_STORAGE], " (actually used)", (ft_uoff) 1 << eff_block_size_log2); } /** start UI, passing I/O object to it. requires I/O to know device length and storage size */ template int fr_work::start_ui() { FT_UI_NS fr_ui * ui = io->ui(); int err = 0; if (ui != NULL) err = ui->start(io); return err; } /** core of remapping algorithm, actually moves DEVICE blocks */ template int fr_work::relocate() { const char * dev_path = io->dev_path(); int err = 0; const bool simulated = io->simulate_run(); const bool ask_questions = io->ask_questions(); const char * simul_msg = simulated ? "(simulated) " : ""; if (!simulated) { err = io->umount_dev(); if (err == 0) { if (ask_questions) { ff_log(FC_NOTICE, 0, "everything ready for in-place remapping, this is your LAST chance to quit."); ff_log(FC_WARN, 0, "press ENTER to proceed, or CTRL+C to quit"); } } else { if (ask_questions) { ff_log(FC_WARN, 0, "please manually unmount %s '%s' before continuing.", label[FC_DEVICE], dev_path); ff_log(FC_WARN, 0, "press ENTER when done, or CTRL+C to quit"); err = 0; } else { const bool is_replaying = io->is_replaying(); ff_log(is_replaying ? FC_WARN : FC_ERROR, 0, "unmount %s '%s' failed", label[FC_DEVICE], dev_path); ff_log(is_replaying ? FC_WARN : FC_ERROR, 0, " you could unmount it yourself and continue"); if (is_replaying) { ff_log(FC_WARN, 0, " but this is a non-interactive job resume, so fsremap will try to continue anyway"); err = 0; } else { ff_log(FC_ERROR, 0, " but this is a non-interactive run, so fsremap will exit now"); ff_log(FC_ERROR, 0, "exiting."); } } } if (ask_questions) { char ch; if (::read(0, &ch, 1) < 0) err = ff_log(FC_ERROR, errno, "read(stdin) failed"); } if (err) return err; } ff_log(FC_NOTICE, 0, "%sstarting in-place remapping. this may take a LONG time ...", simul_msg); ft_uoff eff_block_size_log2 = io->effective_block_size_log2(); /* storage_count = number of storage blocks */ T storage_count = (T) ((io->job_storage_size(FC_PRIMARY_STORAGE_EXACT_SIZE) + io->job_storage_size(FC_SECONDARY_STORAGE_EXACT_SIZE)) >> eff_block_size_log2); /* storage starts free */ storage_map.clear(); storage_map.total_count(storage_count); storage_transpose.clear(); storage_free.insert0(0, 0, storage_count, FC_DEFAULT_USER_DATA); work_total = dev_map.used_count(); /* device starts (almost) full */ T dev_free_count = 0; map_const_iterator iter = dev_free.begin(), end = dev_free.end(); for (; iter != end; ++iter) dev_free_count += iter->second.length; dev_map.total_count(work_total + dev_free_count); dev_transpose.transpose(dev_map); /* * do we have an odd-sized (i.e. smaller than effective block size) last loop-file block? * it must be treated specially, see the next function for details. */ if ((err = check_last_block()) != 0) return err; /* initialize progress report */ eta.clear(); eta.add(0.0); err = update_persistence(); while (err == 0 && !(dev_map.empty() && storage_map.empty())) { if (!dev_map.empty() && !storage_free.empty()) err = fill_storage(); if (err == 0) err = update_persistence(); if (err == 0) show_progress(FC_NOTICE); if (err == 0 && !dev_map.empty()) err = move_to_target(FC_FROM_DEV); if (err == 0) err = update_persistence(); if (err == 0 && !storage_map.empty()) err = move_to_target(FC_FROM_STORAGE); if (err == 0) err = update_persistence(); } if (err == 0) ff_log(FC_INFO, 0, "%sblocks remapping completed.", simul_msg); return err; } /** read or write next step from persistence file */ template int fr_work::update_persistence() { T dev_used = dev_map.used_count(), storage_used = storage_map.used_count(); return io->persist().next((ft_ull) dev_used, (ft_ull) storage_used); } /** show progress status and E.T.A. */ template void fr_work::show_progress(ft_log_level log_level) { const char * simul_msg = io->simulate_run() ? "(simulated) " : io->is_replaying() ? "(replaying) " : ""; const ft_uoff eff_block_size_log2 = io->effective_block_size_log2(); T dev_used = dev_map.used_count(), storage_used = storage_map.used_count(); ft_uoff total_len = ((ft_uoff)dev_used + (ft_uoff)storage_used) << eff_block_size_log2; double percentage = 0.0, time_left = -1.0; if (work_total != 0) { percentage = 1.0 - ((double)dev_used + 0.5 * (double)storage_used) / (double)work_total; /* underestimate the progress percentage: algorithm slows down near the end */ /* time_left = eta.add(percentage); */ double x = percentage; time_left = eta.add(0.5*x + 0.5*x*x); percentage *= 100.0; } ff_show_progress(log_level, simul_msg, percentage, total_len, " still to remap", time_left); const ft_uoff eff_block_size = (ft_uoff)1 << eff_block_size_log2; dev_map.show(label[FC_DEVICE], "", eff_block_size, FC_DUMP); dev_free.show(label[FC_DEVICE], " free space", eff_block_size, FC_DUMP); storage_map.show(label[FC_STORAGE], "", eff_block_size, FC_DUMP); storage_free.show(label[FC_STORAGE], " free space", eff_block_size, FC_DUMP); } /** * called once by relocate() immediately before starting the remapping phase. * * 1) check that last device block to be written is actually writable. * Reason: at least on Linux, if a filesystems is smaller than its containing device, * it often limits to its length the writable blocks in the device. * * 2) check for corner care where we have an odd-sized (i.e. smaller than effective block size) last device block, * which does not appear in any extent map: its length is zero in 1-block units ! * * by itself it is not a problem and we could just ignore it, * but it is likely that an equally odd-sized (or slightly smaller) last loop-file block will be present, * and since its length is instead rounded UP to one block by the various io->read_extents() functions, * the normal algorithm in relocate() would not find its final destination and enter an infinite loop (ouch) */ template int fr_work::check_last_block() { ft_uoff eff_block_size_log2 = io->effective_block_size_log2(); ft_uoff eff_block_size = (ft_uoff) 1 << eff_block_size_log2; ft_uoff dev_len = io->dev_length(), loop_file_len = io->loop_file_length(); dev_len &= ~(eff_block_size - 1); if (loop_file_len <= dev_len) return io->check_last_block(); ft_uoff odd_block_len = loop_file_len & (eff_block_size - 1); const char * simul_msg = io->simulate_run() ? "(simulated) " : ""; ff_log(FC_ERROR, 0, "%s%s has an odd-sized last block (%" FT_ULL " bytes long) that exceeds device rounded length.", simul_msg, label[FC_LOOP_FILE], (ft_ull) odd_block_len); ff_log(FC_ERROR, 0, "%sExiting, please shrink %s to %" FT_ULL " bytes or less before running fsremap again.", simul_msg, label[FC_LOOP_FILE], (ft_ull) dev_len); return -EFBIG; } /** called by relocate(). move as many extents as possible from DEVICE to STORAGE */ template int fr_work::fill_storage() { map_iterator from_iter = dev_map.begin(), from_pos, from_end = dev_map.end(); T moved = 0, from_used_count = dev_map.used_count(), to_free_count = storage_map.free_count(); const bool simulated = io->simulate_run(); const bool replaying = io->is_replaying(); const char * simul_msg = simulated ? "(simulated) " : replaying ? "(replaying) " : ""; double pretty_len = 0.0; const char * pretty_label = ff_pretty_size((ft_uoff)ff_min2(from_used_count, to_free_count) << io->effective_block_size_log2(), & pretty_len); ff_log(FC_INFO, 0, "%sfilling %s by moving %.2f %sbytes from %s ...", simul_msg, label[FC_STORAGE], pretty_len, pretty_label, label[FC_DEVICE]); fr_extent::show(); /* show extents header */ ft_size counter = 0; int err = 0; while (err == 0 && moved < to_free_count && from_iter != from_end) { /* fully or partially move this extent to STORAGE */ from_pos = from_iter; ++from_iter; /* note: some blocks may have been moved even in case of errors! */ err = move(counter++, from_pos, FC_DEV2STORAGE, moved); } if (err == 0) { if ((err = io->flush()) == 0) ff_log(FC_INFO, 0, "%sstorage filled", simul_msg); else { /* error should has been reported by io->flush() */ if (!ff_log_is_reported(err)) err = ff_log(FC_ERROR, err, "%sio->flush() failed with unreported error", simul_msg); } } return err; } /** * called by fill_storage(). * move as much as possible of a single extent from DEVICE to FREE-STORAGE or from STORAGE to FREE-DEVICE. * invalidates from_iter. * note: the extent could be fragmented in the process */ template int fr_work::move(ft_size counter, map_iterator from_iter, fr_dir dir, T & ret_moved) { T moved, length = from_iter->second.length; const bool is_to_dev = ff_is_to_dev(dir); map_stat_type & to_map = is_to_dev ? dev_map : storage_map; map_type & to_free_map = is_to_dev ? dev_free : storage_free; map_iterator to_free_iter = to_free_map.begin(), to_free_pos, to_free_end = to_free_map.end(); int err = 0; if (ff_logl_is_enabled("extent", 6/*strlen("extent")*/, FC_SHOW_DEFAULT_LEVEL)) { const map_value_type & extent = *from_iter; fr_extent::show(counter, extent.first.physical, extent.second.logical, ff_min2(extent.second.length, to_map.free_count()), extent.second.user_data); } while (err == 0 && length != 0 && to_free_iter != to_free_end) { to_free_pos = to_free_iter; ++to_free_iter; moved = 0; err = move_fragment(from_iter, to_free_pos, dir, moved); length -= moved; ret_moved += moved; } if (err == 0) ff_assert(length == 0 || to_map.free_count() == 0); return err; } /** * called by move(). * move a single extent or a fragment of it from DEVICE to FREE STORAGE or from STORAGE to FREE-DEVICE. * the moved amount is the smaller between (from_length = from_iter->length) and (to_length = to_free_iter->length). * * updates dev_* and storage_* maps. * * if from_length <= to_length, invalidates from_iter. * if from_length >= to_length, invalidates to_iter. */ template int fr_work::move_fragment(map_iterator from_iter, map_iterator to_free_iter, fr_dir dir, T & ret_queued) { map_value_type & from_extent = *from_iter, & to_free_extent = *to_free_iter; map_mapped_type & from_value = from_extent.second; T from_length = from_value.length, to_free_length = to_free_extent.second.length; T length = ff_min2(from_length, to_free_length); T from_physical = from_extent.first.physical; T to_physical = to_free_extent.first.physical; int err = io->copy(dir, from_physical, to_physical, length); if (err != 0) return err; /** io->copy() returned success. trust that it copied exactly 'length' blocks */ ret_queued += length; /* * some blocks were copied (or queued for copying). * update 'from' and 'to' maps also in case of errors, * since we know how many blocks were actually copied */ T logical = from_value.logical; ft_size user_data = from_extent.second.user_data; /* update the 'to' maps */ { const bool is_to_dev = ff_is_to_dev(dir); map_stat_type & to_map = is_to_dev ? dev_map : storage_map; to_map.stat_insert(to_physical, logical, length, user_data); map_type & to_transpose = is_to_dev ? dev_transpose : storage_transpose; to_transpose.insert(logical, to_physical, length, user_data); map_type & to_free = is_to_dev ? dev_free : storage_free; /* * erase to_free_iter completely (if moved == to_free_length), * or shrink it (if moved < to_free_length) */ to_free.remove_front(to_free_iter, length); } /* update the 'from' maps */ { const bool is_from_dev = ff_is_from_dev(dir); map_stat_type & from_map = is_from_dev ? dev_map : storage_map; /* beware: this could be a _partial_ remove! */ from_map.stat_remove_front(from_iter, length); /* can invalidate from_iter, from_extent, from_value */ map_type & from_transpose = is_from_dev ? dev_transpose : storage_transpose; from_transpose.remove(logical, from_physical, length); map_type & from_free = is_from_dev ? dev_free : storage_free; from_free.insert(from_physical, from_physical, length, FC_DEFAULT_USER_DATA); } return err; } /** called by relocate(). move as many extents as possible from DEVICE or STORAGE directly to their final destination */ template int fr_work::move_to_target(fr_from from) { map_type movable; map_stat_type & from_map = from == FC_FROM_DEV ? dev_map: storage_map; map_type & from_free = from == FC_FROM_DEV ? dev_free: storage_free; map_type & from_transpose = from == FC_FROM_DEV ? dev_transpose : storage_transpose; const char * label_from = label[from == FC_FROM_DEV ? FC_DEVICE : FC_STORAGE]; const fr_dir dir = from == FC_FROM_DEV ? FC_DEV2DEV : FC_STORAGE2DEV; int err = 0; const bool simulated = io->simulate_run(); const char * simul_msg = simulated ? "(simulated) " : io->is_replaying() ? "(replaying) " : ""; /* find all DEVICE or STORAGE extents that can be moved to their final destination into DEVICE free space */ movable.intersect_all_all(from_transpose, dev_free, FC_PHYSICAL1); if (movable.empty()) { ff_log(FC_INFO, 0, "%smoved 0 bytes from %s to target (not so useful)", simul_msg, label_from); ft_uoff eff_block_size = (ft_uoff)1 << io->effective_block_size_log2(); from_transpose.show(label_from, " transposed", eff_block_size); dev_free.show(label[FC_DEVICE], " free space", eff_block_size); return err; } if (ff_log_is_enabled(FC_INFO)) { map_const_iterator iter = movable.begin(), end = movable.end(); ft_uoff movable_length = 0; for (; iter != end; ++iter) movable_length += iter->second.length; movable_length <<= io->effective_block_size_log2(); double pretty_len = 0.0; const char * pretty_label = ff_pretty_size(movable_length, & pretty_len); ff_log(FC_INFO, 0, "%smoving %.2f %sbytes from %s to target ...", simul_msg, pretty_len, pretty_label, label_from); fr_extent::show(); /* show extents header */ } /* move them */ map_const_iterator iter = movable.begin(), end = movable.end(); T from_physical, to_physical, length; ft_size counter = 0; for (; iter != end; ++iter) { const map_value_type & extent = *iter; from_physical = extent.second.logical; to_physical = extent.first.physical; length = extent.second.length; /* sequential disk access: consecutive calls to io->copy() are sorted by to_physical, i.e. device to_offset */ err = io->copy(dir, from_physical, to_physical, length); fr_extent::show(counter++, from_physical, to_physical, length, extent.second.user_data); if (err != 0) return err; from_transpose.remove(extent); from_map.stat_remove(from_physical, to_physical, length); from_free.insert(from_physical, from_physical, length, FC_DEFAULT_USER_DATA); /* * forget final destination extent: it's NOT free anymore, but nothing to do there. * actually, if it is DEVICE-RENUMBERED, it will likely be cleared after relocate() finishes, * but in such case it is supposed to be ALREADY in toclear_map */ dev_free.remove(to_physical, to_physical, length); dev_map.total_count(dev_map.total_count() - length); } if ((err = io->flush()) == 0) ff_log(FC_INFO, 0, "%sfinished moving from %s to target", simul_msg, label_from); else { /* error should has been reported by io->flush() */ if (!ff_log_is_reported(err)) err = ff_log(FC_ERROR, err, "%s%s move_to_target(): io->flush() failed with unreported error", simul_msg, label_from); } return err; } /** * called by run() after relocate(). depending on job_clear, it will: * 1) if job_clear == FC_CLEAR_ALL, fill with zeroes all free space * 2) if job_clear == FC_CLEAR_MINIMAL, fill with zeroes PRIMARY-STORAGE, DEVICE-RENUMBERED and LOOP-FILE "unwritten" extents * 3) if job_clear == FC_CLEAR_NONE, only fill with zeroes LOOP-FILE "unwritten" extents */ template int fr_work::clear_free_space() { const char * sim_msg = io->simulate_run() ? "(simulated) " : ""; int err = 0; fr_clear_free_space job_clear = io->job_clear(); do { ft_uoff toclear_len = 0; if (job_clear == FC_CLEAR_MINIMAL) toclear_len += (ft_uoff) io->job_storage_size(FC_PRIMARY_STORAGE_EXACT_SIZE); map_const_iterator iter = toclear_map.begin(), end = toclear_map.end(); for (; iter != end; ++iter) toclear_len += (ft_uoff) iter->second.length << io->effective_block_size_log2(); double pretty_len = 0.0; const char * pretty_label = ff_pretty_size(toclear_len, & pretty_len); switch (job_clear) { case FC_CLEAR_MINIMAL: ff_log(FC_NOTICE, 0, "%sclearing %.2f %sbytes free space from %s to remove temporary data (%s and %s backup)...", sim_msg, pretty_len, pretty_label, label[FC_DEVICE], label[FC_PRIMARY_STORAGE], label[FC_DEVICE]); err = io->zero_primary_storage(); break; default: case FC_CLEAR_ALL: case FC_CLEAR_NONE: ff_log(FC_NOTICE, 0, "%sclearing %.2f %sbytes %s from %s ...", sim_msg, pretty_len, pretty_label, job_clear == FC_CLEAR_NONE ? "UNWRITTEN blocks" : label[FC_FREE_SPACE], label[FC_DEVICE]); break; } if (err != 0) break; iter = toclear_map.begin(); end = toclear_map.end(); for (; iter != end; ++iter) { const map_value_type & extent = *iter; #if 0 // some filesystems *MAY* leave their first block unused, so this check is too strict if (extent.first.physical == 0) { ff_log(FC_FATAL, 0, "PANIC! this is a BUG in fsremap! tried to clear first block of remapped device!"); ff_log(FC_FATAL, 0, "\tABORTED clearing %s free space to prevent filesystem corruption.", label[FC_DEVICE]); ff_log(FC_FATAL, 0, "\tSuspending process to allow debugging... press ENTER or CTRL+C to quit."); char ch; if (::read(0, &ch, 1) < 0) { ff_log(FC_WARN, errno, "read(stdin) failed"); } err = -EFAULT; break; } else #endif // 0 if ((err = io->zero(FC_TO_DEV, extent.first.physical, extent.second.length)) != 0) break; } int err2; if ((err2 = io->flush()) != 0) { if (err == 0) err = err2; break; } ff_log(FC_INFO, 0, "%s%s %s cleared", sim_msg, label[FC_DEVICE], job_clear == FC_CLEAR_NONE ? "UNWRITTEN blocks" : job_clear == FC_CLEAR_MINIMAL ? "temporary data" : label[FC_FREE_SPACE]); } while (0); return err; } /** called after relocate() and clear_free_space(). closes storage */ template int fr_work::close_storage_after_success() { int err = io->close_storage(); if (err == 0) err = io->remove_storage_after_success(); return err; } FT_NAMESPACE_END fstransform-0.9.4/fstransform/000077500000000000000000000000001345021500300164255ustar00rootroot00000000000000fstransform-0.9.4/fstransform/.cproject000066400000000000000000000305361345021500300202460ustar00rootroot00000000000000 fstransform-0.9.4/fstransform/.project000066400000000000000000000014541345021500300201000ustar00rootroot00000000000000 fstransform org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder full,incremental, org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature fstransform-0.9.4/fstransform/.settings/000077500000000000000000000000001345021500300203435ustar00rootroot00000000000000fstransform-0.9.4/fstransform/.settings/language.settings.xml000066400000000000000000000040401345021500300245050ustar00rootroot00000000000000 fstransform-0.9.4/fstransform/build/000077500000000000000000000000001345021500300175245ustar00rootroot00000000000000fstransform-0.9.4/fstransform/build/Makefile.am000066400000000000000000000005711345021500300215630ustar00rootroot00000000000000sbin_SCRIPTS = fstransform fstransform: ../fstransform-sh sed 's/%PACKAGE_VERSION%/$(PACKAGE_VERSION)/g' <$< >fstransform.tmp if test -x /bin/dash ; then \ sed 's_#!/bin/bash_#!/bin/dash_g' $@ ; \ rm -f fstransform.tmp ; \ else \ mv fstransform.tmp $@ ; \ fi chmod +x $@ ../fstransform-sh: clean: clean-am rm -f fstransform fstransform.tmp fstransform-0.9.4/fstransform/build/Makefile.am.work000066400000000000000000000002511345021500300225370ustar00rootroot00000000000000AUTOMAKE_OPTIONS = subdir-objects sbin_PROGRAMS = fstransform fstransform_SOURCES = \ ../src/log.cc \ ../src/main.cc \ ../src/mstring.cc \ ../src/transform.cc fstransform-0.9.4/fstransform/build/Makefile.in000066400000000000000000000345651345021500300216060ustar00rootroot00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = fstransform/build ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/tools/ft_cxx_flags.m4 \ $(top_srcdir)/tools/ft_cxx_features.m4 \ $(top_srcdir)/tools/ft_cxx_unordered_map.m4 \ $(top_srcdir)/tools/ft_need_funcs.m4 \ $(top_srcdir)/tools/ft_need_libs.m4 \ $(top_srcdir)/tools/ft_output.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/fsremap/src/config.hh CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(sbindir)" SCRIPTS = $(sbin_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LD_LIBCOM_ERR = @LD_LIBCOM_ERR@ LD_LIBEXT2FS = @LD_LIBEXT2FS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CXX = @ac_ct_CXX@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ sbin_SCRIPTS = fstransform all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu fstransform/build/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu fstransform/build/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-sbinSCRIPTS: $(sbin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(sbin_SCRIPTS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(sbin_SCRIPTS)'; test -n "$(sbindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(sbindir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(SCRIPTS) installdirs: for dir in "$(DESTDIR)$(sbindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinSCRIPTS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-sbinSCRIPTS .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic cscopelist-am \ ctags-am distclean distclean-generic distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-sbinSCRIPTS install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags-am uninstall uninstall-am \ uninstall-sbinSCRIPTS .PRECIOUS: Makefile fstransform: ../fstransform-sh sed 's/%PACKAGE_VERSION%/$(PACKAGE_VERSION)/g' <$< >fstransform.tmp if test -x /bin/dash ; then \ sed 's_#!/bin/bash_#!/bin/dash_g' $@ ; \ rm -f fstransform.tmp ; \ else \ mv fstransform.tmp $@ ; \ fi chmod +x $@ ../fstransform-sh: clean: clean-am rm -f fstransform fstransform.tmp # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: fstransform-0.9.4/fstransform/fstransform-sh000077500000000000000000001266321345021500300213410ustar00rootroot00000000000000#!/bin/bash # # fstransform - transform a file-system to another file-system type, # preserving its contents and without the need for a backup # # Copyright (C) 2012 Massimiliano Ghilardi # # 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 . # # fstranform.sh # # Created on: Jan 21, 2012 # Author: max # ____=' ' PROG=fstransform PROG_VERSION=%PACKAGE_VERSION% BOOT_CMD_which=which CMDS_bootstrap="which expr id" CMDS="stat mkfifo blockdev losetup fsck mkfs mount umount mkdir rmdir rm dd sync fsmove fsmount_kernel fsremap" # optional commands CMDS_optional="sleep date" # commands that are optional or required, depending on --prealloc command-line option CMDS_prealloc="fsattr" # commands that may need different variants for source and target file-systems CMDS_dual="fsck" # commands not found in environment CMDS_missing= # start with a clean environment ERR=0 DEVICE= FSTYPE= # nilfs2 is under test, works as target but as fails as source: gets full with usage = 100% # ocfs2 and reiserfs4 are under test, got kernel crash testing them # ntfs is under test. ntfs->ext4 gives nasty "/dev/loop0: I/O error" kernel messages # ntfs->ext2 seems to work but FUSE ntfs-3g is unbearably slow on large files FSTYPES_TESTED="ext2 ext3 ext4 reiserfs jfs xfs" DEVICE_BLOCK_SIZE= DEVICE_SIZE_IN_BYTES= DEVICE_SIZE_IN_BLOCKS= DEVICE_IS_INITIALLY_MOUNTED= DEVICE_MOUNT_POINT= DEVICE_MOUNT_OPTS_RW=rw DEVICE_FSTYPE= LOOP_FILE= LOOP_DEVICE= LOOP_SIZE_IN_BYTES= LOOP_MOUNT_POINT= LOOP_MOUNT_OPTS_RW=rw ZERO_FILE= OPT_CREATE_ZERO_FILE=no OPT_ASK_QUESTIONS=yes OPT_TTY_SHOW_TIME=yes OPT_PREALLOC= OPTS_fsattr= OPTS_fsmove= OPTS_fsremap= OPTS_fsmount_kernel= OPTS_mkfs="-q" OPTS_fsck_source="-p -f" OPTS_fsck_target="-p -f" X_COPY_LOOP_FILE= X_COPY_DEVICE= USER_ANSWER= USER_LOOP_SIZE_IN_BYTES= USER_FORCE_UNTESTED_FSTYPES= for cmd in $CMDS_bootstrap $CMDS $CMDS_maybe_required $CMDS_optional; do eval "CMD_$cmd=" done for cmd in $CMDS_dual; do eval "CMD_${cmd}_source=" eval "CMD_${cmd}_target=" done TMP_DIR="/tmp" VAR_TMP_DIR="/var/tmp" FIFO_OUT="$TMP_DIR/fstransform.out.$$" FIFO_ERR="$TMP_DIR/fstransform.err.$$" PROG_DIR="$VAR_TMP_DIR/fstransform" PROG_LOG_FILE="$VAR_TMP_DIR/fstransform/fstransform.log.$$" # after log_init_file(), file descriptor 5 will be log file ~/.fstransform/fstransform.$$ exec 5>/dev/null # after log_init_{tty,gui}(), file descriptor 1 will be tty or gui file descriptor show_usage() { echo "Usage: $0 [OPTION]... DEVICE NEW-FILE-SYSTEM-TYPE" echo "Transform file system inside DEVICE to NEW-FILE-SYSTEM-TYPE," echo "preserving its contents and without need for backup" echo echo "Options:" echo " --cmd-CMD-NAME=CMD-PATH set external command CMD-NAME to use." echo " default: autodetect" echo " --force-untested-file-systems also transform untested file systems (DANGEROUS)" echo " --list-source-file-systems list file systems supported as source and exit" echo " --list-target-file-systems list file systems supported as target and exit" echo " --loop-file=LOOP-FILE override loop-file path" echo " --loop-mount-point=PATH override loop-file mount point" echo " --new-size=SIZE set new file system length. default: device length" echo " --current-fstype=OLD-TYPE override current (old) file system type autodetection" echo " required for 'ntfs' file system" echo " --opts-fsmove=OPTS pass OPTS as additional options to 'fsmove'" echo " --opts-fsremap=OPTS pass OPTS as additional options to 'fsremap'" echo " --opts-mkfs=OPTS pass OPTS as options to 'mkfs'. default: '-q'" echo " --opts-fsck-source=OPTS override 'fsck' options for old file system. default: '-p -f'" echo " --opts-fsck-target=OPTS override 'fsck' options for new file system. default: '-p -f'" echo " --show-time[=yes|=no] show current time before each message. default: yes" echo " --prealloc[=yes|no] use EXPERIMENTAL files preallocation. default: no" echo " --questions=[yes|no|on-error] whether to ask questions interactively. default: on-error" echo " --reversible[=yes|no] create zero-file, fsremap will do a reversible transformation" echo " default: no" echo " --x-OPTION=VALUE set internal, undocumented option. For maintainers only." echo " --zero-file=ZERO-FILE override zero-file path" echo " --help display this help and exit" echo " --version output version information and exit" } show_version() { echo "fstransform (fstransform utilities) $PROG_VERSION" echo "Copyright (C) 2011-2017 Massimiliano Ghilardi" echo "" echo "License GPLv3+: GNU GPL version 3 or later ." echo "This is free software: you are free to change and redistribute it." echo "There is NO WARRANTY, to the extent permitted by law." } show_tested_fstypes() { for fstype in $FSTYPES_TESTED; do echo "$fstype" done } if test "$#" = 1; then case "$1" in --help) show_usage; exit 0;; --version) show_version; exit 0;; --list-source-file-systems) show_tested_fstypes; exit 0;; --list-target-file-systems) show_tested_fstypes; exit 0;; esac fi # parse command line arguments and set USER_CMD_* variables accordingly parse_args() { log_info "parsing command line arguments" for arg in "$@"; do case "$arg" in --cmd-*=* ) cmd="`\"$CMD_expr\" match \"$arg\" '--cmd-\(.*\)=.*'`" user_cmd="`\"$CMD_expr\" match \"$arg\" '--cmd-.*=\(.*\)'`" eval "USER_CMD_$cmd='$user_cmd'" ;; --force-untested-file-systems) USER_FORCE_UNTESTED_FSTYPES="yes" log_info "forcing trasformation of untested file systems (DANGEROUS). '$arg' bytes specified on command line" ;; --loop-file=*) LOOP_FILE="`\"$CMD_expr\" match \"$arg\" '--loop-file=\(.*\)'`" log_info "loop file '$LOOP_FILE' specified on command line" ;; --loop-mount-point=*) LOOP_MOUNT_POINT="`\"$CMD_expr\" match \"$arg\" '--loop-mount-point=\(.*\)'`" log_info "loop file mount point '$LOOP_MOUNT_POINT' specified on command line" ;; --new-size=*) USER_LOOP_SIZE_IN_BYTES="`\"$CMD_expr\" match \"$arg\" '--new-size=\(.*\)'`" log_info "device new (final) file-system length '$USER_LOOP_SIZE_IN_BYTES' bytes specified on command line" ;; --current-fstype=*) DEVICE_FSTYPE="`\"$CMD_expr\" match \"$arg\" '--current-fstype=\(.*\)'`" log_info "device initial (current) file-system type '$DEVICE_FSTYPE' specified on command line" ;; --opts-fsmove=*) OPTS_fsmove="`\"$CMD_expr\" match \"$arg\" '--opts-fsmove=\(.*\)'`" log_info "options '$OPTS_fsmove' for fsmove specified on command line" ;; --opts-fsremap=*) OPTS_fsremap="`\"$CMD_expr\" match \"$arg\" '--opts-fsremap=\(.*\)'`" log_info "options '$OPTS_fsremap' for fsremap specified on command line" ;; --opts-mkfs=*) OPTS_mkfs="`\"$CMD_expr\" match \"$arg\" '--opts-mkfs=\(.*\)'`" log_info "options '$OPTS_mkfs' for mkfs specified on command line" ;; --opts-fsck-source=*) OPTS_fsck_source="`\"$CMD_expr\" match \"$arg\" '--opts-fsck-source=\(.*\)'`" log_info "options '$OPTS_fsck_source' for fsck(source file-system) specified on command line" ;; --opts-fsck-target=*) OPTS_fsck_target="`\"$CMD_expr\" match \"$arg\" '--opts-fsck-target=\(.*\)'`" log_info "options '$OPTS_FSCK_TARGET_FS' for fsck(target file-system) specified on command line" ;; --prealloc|--prealloc=*) # handled in parse_args_late() below ;; --questions=yes|--interactive) OPT_ASK_QUESTIONS=yes log_info "assuming interactive execution, '$arg' specified on command line" ;; --questions=on-error) OPT_ASK_QUESTIONS=on-error log_info "assuming interactive execution, '$arg' specified on command line" ;; --questions=no|--no-questions) OPT_ASK_QUESTIONS=no log_info "assuming non-interactive execution, '$arg' specified on command line" ;; --reversible|--reversible=yes) OPT_CREATE_ZERO_FILE=yes log_info "zero file will be created, '$arg' specified on command line" ;; --reversible=no) OPT_CREATE_ZERO_FILE=no log_info "skipping creation of zero file, '$arg' specified on command line" ;; --show-time|--show-time=yes) OPT_TTY_SHOW_TIME=yes log_info "showing time-of-day for each message, '$arg' specified on command line" ;; --show-time=no) OPT_TTY_SHOW_TIME=no log_info "hiding time-of-day for each message, '$arg' specified on command line" ;; --x-copy-device=*) X_COPY_DEVICE="`\"$CMD_expr\" match \"$arg\" '--x-copy-device=\(.*\)'`" log_info "(internal option) device will be copied to '$X_COPY_DEVICE' just before remapping" ;; --x-copy-loop-file=*) X_COPY_LOOP_FILE="`\"$CMD_expr\" match \"$arg\" '--x-copy-loop-file=\(.*\)'`" CMDS="$CMDS cmp" CMD_cmp= log_info "(internal option) loop file will be copied to '$X_COPY_LOOP_FILE'" log_info_add "command 'cmp' will be needed to verify it after transformation." ;; --zero-file=*) ZERO_FILE="`\"$CMD_expr\" match \"$arg\" '--zero-file=\(.*\)'`" log_info "zero file '$ZERO_FILE' specified on command line" ;; --*) log_warn "ignoring unknown option '$arg'" ;; *) if test "$DEVICE" = ""; then DEVICE="$arg" elif test "$FSTYPE" = ""; then FSTYPE="$arg" else log_info "ignoring extra argument '$arg'" fi ;; esac done } parse_args_late() { for arg in "$@"; do case "$arg" in --prealloc=yes-i-want-to-lose-my-data) OPT_PREALLOC=yes log_warn "trying to enable EXPERIMENTAL files preallocation," log_warn_add "option '$arg' specified on command line." log_warn_add "be prepared to LOSE your data!" if test "$CMD_sleep" != ""; then log_warn_add "continuing in 5 seconds..." "$CMD_sleep" 5 fi log_warn_add ;; --prealloc|--prealloc=yes) OPT_PREALLOC=no log_warn "preallocation is EXPERIMENTAL and not well tested. if you really want to enable it," log_warn_add "specify '--prealloc=yes-i-want-to-lose-my-data' on command line and be prepared to LOSE your data." if test "$CMD_sleep" != ""; then log_warn_add "continuing in 5 seconds without preallocation..." "$CMD_sleep" 5 fi log_warn_add ;; --prealloc=no) OPT_PREALLOC=no log_info "disabling preallocation, '$arg' specified on command line" ;; esac done } log_def_file() { log_file_timestamp() { if test "$CMD_date" != ""; then echo -n "`\"$CMD_date\" \"+%Y-%m-%d %H:%M:%S\"` " 1>&5 fi } log_file_no_timestamp() { if test "$CMD_date" != ""; then echo -n " " 1>&5 fi } log_file_info_4_cmd() { log_file_timestamp echo "$@" 1>&5 } log_file_info() { log_file_timestamp echo "$PROG: $@" 1>&5 } log_file_info_add() { log_file_no_timestamp echo "$____ $@" 1>&5 } log_file_start() { log_file_timestamp echo -n "$PROG: $@" 1>&5 } log_file_end() { log_file_timestamp echo "$@" 1>&5 } log_file_warn() { log_file_no_timestamp echo 1>&5 log_file_timestamp echo "$PROG: WARNING: $@" 1>&5 } log_file_warn_add() { log_file_no_timestamp echo "$____ $@" 1>&5 } log_file_warn_add_prompt() { log_file_no_timestamp echo "$____ $@" 1>&5 } log_file_err() { log_file_no_timestamp echo 1>&5 log_file_timestamp echo "ERROR! $PROG: $@" 1>&5 } log_file_err_add() { log_file_no_timestamp echo " $@" 1>&5 } log_file_err_add_prompt() { log_file_no_timestamp echo " $@" 1>&5 } } log_init_file() { "$CMD_mkdir" -p "$PROG_DIR" >/dev/null 2>&1 > "$PROG_LOG_FILE" >/dev/null 2>&1 if test -w "$PROG_LOG_FILE"; then exec 5>"$PROG_LOG_FILE" fi } log_def_tty() { read_user_answer() { if test "$OPT_ASK_QUESTIONS" = "no"; then USER_ANSWER= else read USER_ANSWER fi } log_tty_timestamp() { if test "$OPT_TTY_SHOW_TIME" = "yes" -a "$CMD_date" != ""; then echo -n "`\"$CMD_date\" \"+%H:%M:%S\"` " fi } log_tty_no_timestamp() { if test "$OPT_TTY_SHOW_TIME" = "yes" -a "$CMD_date" != ""; then echo -n " " fi } log_info_4_cmd() { log_tty_timestamp echo "$@" log_file_info_4_cmd "$@" } log_info() { log_tty_timestamp echo "$PROG: $@" log_file_info "$@" } log_info_add() { log_tty_no_timestamp echo "$____ $@" log_file_info_add "$@" } log_start() { log_tty_timestamp echo -n "$PROG: $@" log_file_start "$@" } log_end() { echo "$@" log_file_end "$@" } log_warn() { log_tty_no_timestamp echo log_tty_timestamp echo "$PROG: WARNING: $@" log_file_warn "$@" } log_warn_add() { log_tty_no_timestamp echo "$____ $@" log_file_warn_add "$@" } log_warn_add_prompt() { log_tty_no_timestamp echo -n "$____ $@" log_file_warn_add_prompt "$@" } log_err() { log_tty_no_timestamp echo log_tty_timestamp echo "ERROR! $PROG: $@" log_file_err "$@" } log_err_add() { log_tty_no_timestamp echo " $@" log_file_err_add "$@" } log_err_add_prompt() { log_tty_no_timestamp echo -n " $@" log_file_err_add_prompt "$@" } } log_init_tty() { log_quit() { # tty implementation of log_quit(): nothing to do return 0 } return 0 } log_quit() { # default implementation of log_quit(): nothing to do return 0 } log_def_file log_init_tty && log_def_tty ERR="$?" if test "$ERR" != 0; then echo "failed to initialize output to tty!" echo "exiting." exit "$ERR" fi log_info "starting version $PROG_VERSION, checking environment" detect_cmd() { local my_cmd_which="$CMD_which" if test "$my_cmd_which" = ""; then my_cmd_which="$BOOT_CMD_which" fi local cmd="$1" local my_cmd= local user_cmd="`eval echo '$USER_CMD_'\"$cmd\"`" log_start "checking for $cmd... " if test "$user_cmd" != ""; then my_cmd="`$my_cmd_which \"$user_cmd\"`" >/dev/null 2>&1 if test "$my_cmd" != ""; then if test -x "$my_cmd"; then log_end "'$my_cmd' ('$user_cmd' was specified)" eval "CMD_$cmd='$my_cmd'" return 0 fi fi fi my_cmd="`$my_cmd_which \"$cmd\"`" >/dev/null 2>&1 if test "$my_cmd" != ""; then if test -x "$my_cmd"; then log_end "'$my_cmd'" eval "CMD_$cmd='$my_cmd'" return 0 else log_end "found '$my_cmd', but is NOT executable by you!" fi else log_end "NOT FOUND!" fi CMDS_missing="$CMDS_missing '$cmd'" return 1 } detect_cmd_dual() { local my_cmd_which="$CMD_which" if test "$my_cmd_which" = ""; then my_cmd_which="$BOOT_CMD_which" fi local cmd="$1" local source_or_target="$2" local user_cmd="`eval echo '$USER_CMD_'\"$cmd\"'_'\"$source_or_target\"`" local my_cmd= log_start "checking for ${cmd}($source_or_target file-system)... " if test "$user_cmd" != ""; then my_cmd="`$my_cmd_which \"$user_cmd\"`" >/dev/null 2>&1 if test "$my_cmd" != ""; then if test -x "$my_cmd"; then log_end "'$my_cmd' ('$user_cmd' was specified)" eval "CMD_${cmd}_$source_or_target='$my_cmd'" return 0 fi fi fi local nondual_cmd="`eval echo '$CMD_'\"$cmd\"`" log_end "'$nondual_cmd'" eval "CMD_${cmd}_$source_or_target='$nondual_cmd'" return 0 } fix_for_fstype_ntfs() { if test "$DEVICE_FSTYPE" = "ntfs-3g"; then DEVICE_FSTYPE="ntfs" fi if test "$FSTYPE" = "ntfs-3g"; then FSTYPE="ntfs" fi local my_cmd_ntfsresize= if test "$FSTYPE" = "ntfs" -o "$DEVICE_FSTYPE" = "ntfs"; then log_info "applying special options for file-system type 'ntfs'" # we need 'ntfsresize', check if it's available my_cmd_ntfsresize="`$CMD_which ntfsresize`" if test "$my_cmd_ntfsresize" = ""; then log_warn "command 'ntfsresize' not found, it is needed to check integrity of file-system type 'ntfs'" fi fi if test "$DEVICE_FSTYPE" = "ntfs"; then DEVICE_MOUNT_OPTS_RW="rw,big_writes" if test "$my_cmd_ntfsresize" != "" -a "$USER_CMD_fsck_source" = ""; then USER_CMD_fsck_source="ntfsresize" OPTS_fsck_source="-n" detect_cmd_dual "fsck" "source" fi fi if test "$FSTYPE" = "ntfs"; then LOOP_MOUNT_OPTS_RW="rw,big_writes" if test "$my_cmd_ntfsresize" != "" -a "$USER_CMD_fsck_target" = ""; then USER_CMD_fsck_target="ntfsresize" OPTS_fsck_target="-n" detect_cmd_dual "fsck" "target" fi # 'mkfs -t ntfs' needs option '-f' (quick format) to maintain sparse files OPTS_mkfs="$OPTS_mkfs -f" fi } fix_for_fstype_nilfs2() { if test "$DEVICE_FSTYPE" = "nilfs2" -a "$USER_CMD_fsck_target" = ""; then # fsck.nilfs2 does not exist. # use ':', the standard 'do nothing successfully' command. no need to rely on /bin/true USER_CMD_fsck_source=":" fi if test "$FSTYPE" = "nilfs2" -a "$USER_CMD_fsck_target" = ""; then # fsck.nilfs2 does not exist. # use ':', the standard 'do nothing successfully' command. no need to rely on /bin/true USER_CMD_fsck_target=":" fi } fix_for_fstype_xfs() { if test "$DEVICE_FSTYPE" = "xfs" -a "$USER_CMD_fsck_target" = ""; then # fsck.xfs does nothing, use xfs_repair instead. USER_CMD_fsck_source="xfs_repair" fi if test "$FSTYPE" = "xfs" -a "$USER_CMD_fsck_target" = ""; then # fsck.xfs does nothing, use xfs_repair instead. USER_CMD_fsck_target="xfs_repair" fi } # apply fixes for special cases... fix_for_special_cases() { fix_for_fstype_nilfs2 fix_for_fstype_ntfs fix_for_fstype_xfs } fail_missing_cmds() { log_err "environment check failed." log_err_add "Please install the commands$CMDS_missing before running $PROG" log_err_add "If these commands are already installed, add them to your \$PATH" log_err_add "or tell their location with the option --cmd-COMMAND=/path/to/your/command" exit "$ERR" } # bootstrap command detection (command 'which') and argument parsing (command 'expr') for cmd in $CMDS_bootstrap; do detect_cmd "$cmd" || ERR="$?" done if test "$ERR" != 0; then fail_missing_cmds fi check_uid_0() { local my_uid="`$CMD_id -u`" if test "$my_uid" != 0; then log_err "this script must be executed as root (uid 0)" log_err_add "instead it is currently running as uid $my_uid" exit 1 fi } check_uid_0 parse_args "$@" for cmd in $CMDS; do detect_cmd "$cmd" || ERR="$?" done for cmd in $CMDS_dual; do detect_cmd_dual "$cmd" "source" || ERR="$?" detect_cmd_dual "$cmd" "target" || ERR="$?" done log_info "looking for optional commands" for cmd in $CMDS_optional; do detect_cmd "$cmd" done parse_args_late "$@" if test "$OPT_PREALLOC" = yes; then CMDS="$CMDS $CMDS_prealloc" for cmd in $CMDS_prealloc; do detect_cmd "$cmd" || ERR="$?" done fi fix_for_special_cases if test "$ERR" != 0; then fail_missing_cmds fi log_info "environment check passed." ERR=0 check_command_line_args() { local my_missing= if test "$DEVICE" != "" -a "$FSTYPE" != ""; then return 0 elif test "$DEVICE" != ""; then my_missing="argument FSTYPE" elif test "$FSTYPE" != ""; then my_missing="argument DEVICE" else my_missing="arguments DEVICE and FSTYPE" fi log_err "missing command-line $my_missing." log_err "Try '$0 --help' for more information" exit 1 } check_command_line_args # inform if a command failed, and offer to fix manually exec_cmd_status() { if test "$ERR" != 0; then log_err "command '$@' failed (exit status $ERR)" log_err_add "this is potentially a problem." if test "$OPT_ASK_QUESTIONS" = "no"; then log_err_add log_err_add "you could try fix the problem yourself and continue" log_err_add "but this is a non-interactive run, so $PROG will exit now" else log_err_add "you can either quit now by pressing ENTER or CTRL+C," log_err_add log_err_add "or, if you know what went wrong, you can fix it yourself," log_err_add "then manually run the command '$@'" log_err_add "(or something equivalent)" log_err_add_prompt "and finally resume this script by typing CONTINUE and pressing ENTER: " fi read_user_answer if test "$USER_ANSWER" != "CONTINUE"; then log_info 'exiting.' exit "$ERR" fi ERR=0 fi } # treat 'fsck' programs specially: # they exit with status 1 to indicate that file-system errors were corrected exec_cmd_status_fsck() { if test "$ERR" = 1; then log_info "command '$@' returned exit status 1" log_info_add "this means some file-system problems were found and corrected" log_info_add "on ext2, ext3 and ext4 it may simply mean harmless directory optimization" log_info_add "continuing..." ERR=0 else exec_cmd_status "$@" fi } remove_fifo_out_err() { "$CMD_rm" -f "$FIFO_OUT" "$FIFO_ERR" } create_fifo_out_err() { remove_fifo_out_err "$CMD_mkfifo" -m 600 "$FIFO_OUT" "$FIFO_ERR" ERR="$?" exec_cmd_status "$CMD_mkfifo" -m 600 "$FIFO_OUT" "$FIFO_ERR" } create_fifo_out_err CLEANUP_SIGNALS="HUP INT QUIT ILL TRAP ABRT BUS FPE KILL SEGV PIPE TERM URG XCPU XFSZ VTALRM PROF IO PWR SYS" CLEANUP_0= CLEANUP_1= CLEANUP_2= CLEANUP_3= CLEANUP_4= CLEANUP_5= do_cleanup() { trap - 0 $CLEANUP_SIGNALS if test "$CLEANUP_5" != ""; then eval "$CLEANUP_5" >/dev/null 2>/dev/null fi if test "$CLEANUP_4" != ""; then eval "$CLEANUP_4" >/dev/null 2>/dev/null fi if test "$CLEANUP_3" != ""; then eval "$CLEANUP_3" >/dev/null 2>/dev/null fi if test "$CLEANUP_2" != ""; then eval "$CLEANUP_2" >/dev/null 2>/dev/null fi if test "$CLEANUP_1" != ""; then eval "$CLEANUP_1" >/dev/null 2>/dev/null fi if test "$CLEANUP_0" != ""; then eval "$CLEANUP_0" >/dev/null 2>/dev/null fi remove_fifo_out_err log_quit } cleanup_on_exit() { do_cleanup log_quit } cleanup_on_signal() { do_cleanup exit 1 } trap cleanup_on_exit 0 trap cleanup_on_signal $CLEANUP_SIGNALS log_init_file log_info "saving output of this execution into $PROG_LOG_FILE" read_cmd_out_err() { local my_cmd_full="$1" local my_cmd="`\"$CMD_expr\" match \"$1\" '.*/\([^/]*\)'`" if test "$my_cmd" = ""; then my_cmd="$my_cmd_full" fi local my_fifo="$2" local my_prefix="$3" local my_out_1= my_out= while read my_out_1 my_out; do if test "$my_out_1" = "$my_cmd:"; then log_info_4_cmd "$my_prefix$my_cmd: $my_out" elif test "$my_out_1" = "$my_cmd_full:"; then log_info_4_cmd "$my_prefix$my_cmd: $my_out" else log_info_4_cmd "$my_prefix$my_cmd: $my_out_1 $my_out" fi done < "$my_fifo" & } read_cmd_out() { read_cmd_out_err "$1" "$FIFO_OUT" "" } read_cmd_err() { read_cmd_out_err "$1" "$FIFO_ERR" "warn: " } exec_cmd_noquit() { read_cmd_out "$1" "$@" >"$FIFO_OUT" 2>"$FIFO_OUT" ERR="$?" wait } exec_cmd() { exec_cmd_noquit "$@" exec_cmd_status "$@" } # treat 'fsck' programs specially: # they exit with status 1 to indicate that file-system errors were corrected exec_cmd_fsck() { exec_cmd_noquit "$@" exec_cmd_status_fsck "$@" } capture_cmd() { local my_ret my_var="$1" shift read_cmd_out "$1" my_ret="`\"$@\" 2>\"$FIFO_OUT\"`" ERR="$?" wait if test "$ERR" != 0; then log_err "command '$@' failed (exit status $ERR)" exit "$ERR" elif test "$my_ret" = ""; then log_err "command '$@' failed (no output)" exit 1 fi eval "$my_var='$my_ret'" } check_device_is_block_special() { if test ! -b "$DEVICE"; then log_err "argument '$DEVICE' is NOT a block special device! Aborting." exit 1 fi } check_device_is_block_special log_info "preparing to transform device '$DEVICE' to file-system type '$FSTYPE'" echo_device_mount_point_and_fstype() { local my_dev="$1" "$CMD_mount" | while read dev _on_ mount_point _type_ fstype opts; do if test "$dev" = "$my_dev"; then echo "$mount_point $fstype" break fi done } initial_mount_device() { DEVICE_MOUNT_POINT="$TMP_DIR/fstransform.mount.$$" "$CMD_mkdir" -p "$DEVICE_MOUNT_POINT" >/dev/null 2>&1 CLEANUP_0="'$CMD_rmdir' '$DEVICE_MOUNT_POINT'" if test "$DEVICE_FSTYPE" != ""; then exec_cmd "$CMD_mount" "$DEVICE" "$DEVICE_MOUNT_POINT" -t "$DEVICE_FSTYPE" else exec_cmd "$CMD_mount" "$DEVICE" "$DEVICE_MOUNT_POINT" fi CLEANUP_0="'$CMD_umount' '$DEVICE'; $CLEANUP_0" } find_device_mount_point_and_fstype() { local my_dev="$DEVICE" local my_mount_point= my_fstype= my_now= local ret="`echo_device_mount_point_and_fstype \"$my_dev\"`" if test "$ret" = ""; then log_info "device '$my_dev' not found in the output of command $CMD_mount, assuming it is not mounted" initial_mount_device local ret="`echo_device_mount_point_and_fstype \"$my_dev\"`" if test "$ret" = ""; then log_err "just mounted device '$my_dev' at mount point '$DEVICE_MOUNT_POINT'" log_err_add "but still cannot find it in the output of command $CMD_mount" log_err_add "I give up, sorry" exit 1 fi my_now=" now" else DEVICE_IS_INITIALLY_MOUNTED=yes fi for i in $ret; do if test "$my_mount_point" = ""; then my_mount_point="$i" else my_fstype="$i" fi done log_info "device is$my_now mounted at '$my_mount_point' with file-system type '$my_fstype'" if test ! -e "$my_mount_point"; then log_err "mount point '$my_mount_point' does not exist." log_err_add "maybe device '$my_dev' is mounted on a path containing spaces?" log_err_add "$PROG does not support mount points containing spaces in their path" exit 1 fi if test ! -d "$my_mount_point"; then log_err "mount point '$my_mount_point' is not a directory" exit 1 fi DEVICE_MOUNT_POINT="$my_mount_point" if test "$my_fstype" = fuseblk; then if test "$DEVICE_FSTYPE" != ""; then log_info "file-system type '$my_fstype' is a placeholder name for FUSE... ignoring it (user specified type '$DEVICE_FSTYPE')" else log_err "file-system type '$my_fstype' is a placeholder name for FUSE... unable to detect actual file-system type!" log_err_add "please re-run $PROG adding the option --current-fstype={CURRENT_FILE_SYSTEM_TYPE}" log_err_add "as for example --current-fstype=ntfs" log_err_add "exiting now." exit 1 fi elif test "$DEVICE_FSTYPE" != ""; then # let's compare user-specified file-system type with what we found... # still we honour what the user said. if test "$DEVICE_FSTYPE" != "$my_fstype"; then log_warn "does not match user-specified device file-system type '$DEVICE_FSTYPE'. using user-specified value." fi else DEVICE_FSTYPE="$my_fstype" fi } find_device_mount_point_and_fstype check_for_tested_fstypes() { if test "$FSTYPE" = ""; then log_err "target file system type not specified!" exit 1 fi local my_fstype_source_ok=no my_fstype_target_ok=no for my_fstype in $FSTYPES_TESTED; do if test "$DEVICE_FSTYPE" = "$my_fstype"; then my_fstype_source_ok=yes break fi done for my_fstype in $FSTYPES_TESTED; do if test "$FSTYPE" = "$my_fstype"; then my_fstype_target_ok=yes break fi done if test "$my_fstype_source_ok" = "yes" -a "$my_fstype_target_ok" = "yes"; then return 0 fi local my_log=log_err my_log_add=log_err_add if test "$USER_FORCE_UNTESTED_FSTYPES" = "yes"; then my_log=log_warn my_log_add=log_warn_add fi if test "$my_fstype_source_ok" != "yes"; then if test "$DEVICE_FSTYPE" = ""; then "$my_log" "failed to detect device current file system type" else "$my_log" "this program is UNTESTED on device current file system '$DEVICE_FSTYPE' !" fi fi if test "$my_fstype_target_ok" != "yes"; then "$my_log" "this program is UNTESTED on target file system '$FSTYPE' !" fi "$my_log_add" "this program is tested ONLY on file systems: $FSTYPES_TESTED" if test "$USER_FORCE_UNTESTED_FSTYPES" = "yes"; then "$my_log_add" "continuing anyway due to option '--force-untested-file-systems' (DANGEROUS)" return 0 else "$my_log_add" "cowardly refusing to run. if you know what you are doing, you can use" "$my_log_add" "option '--force-untested-file-systems' (DANGEROUS, you can LOSE your DATA)" exit 1 fi } check_for_tested_fstypes check_for_prealloc() { if test "$OPT_PREALLOC" = "yes"; then if test "$FSTYPE" = "ext4"; then # detect if we can use preallocation if test "$CMD_fsattr" != ""; then if "$CMD_fsattr" --help >/dev/null 2>&1; then log_info "enabling EXPERIMENTAL files preallocation: target FSTYPE is '$FSTYPE' and command 'fsattr' is available" OPT_PREALLOC=yes else log_warn "cannot enable EXPERIMENTAL files preallocation: target FSTYPE is '$FSTYPE' but command 'fsattr' is a stub" OPT_PREALLOC=no fi else log_warn "cannot enable EXPERIMENTAL files preallocation: target FSTYPE is '$FSTYPE' but command 'fsattr' is not available" OPT_PREALLOC=no fi else log_warn "cannot enable EXPERIMENTAL files preallocation: currently supported only 'ext4' target, not '$FSTYPE'" OPT_PREALLOC=no fi fi } check_for_prealloc find_device_size() { capture_cmd DEVICE_SIZE_IN_BYTES "$CMD_blockdev" --getsize64 "$DEVICE" log_info "device raw size = $DEVICE_SIZE_IN_BYTES bytes" } find_device_size create_loop_or_zero_file() { local my_kind="$1" my_var="$2" my_file="$3" local my_pattern="$DEVICE_MOUNT_POINT/.fstransform.$my_kind.*" local my_files="`echo $my_pattern`" if test "$my_files" != "$my_pattern"; then log_warn "possibly stale $PROG $my_kind files found inside device '$DEVICE'," log_warn_add "maybe they can be removed? list of files found:" log_warn_add log_warn_add "$my_files" log_warn_add fi if test "$my_file" = ""; then my_file="$DEVICE_MOUNT_POINT/.fstransform.$my_kind.$$" log_info "creating sparse $my_kind file '$my_file' inside device '$DEVICE'..." if test -e "$my_file"; then log_err "$my_kind file '$my_file' already exists! please remove it" exit 1 fi else # check that user-specified file is actually inside DEVICE_MOUNT_POINT "$CMD_expr" match "$my_file" "$DEVICE_MOUNT_POINT/.*" >/dev/null 2>/dev/null || ERR="$?" if test "$ERR" != 0; then log_err "user-specified $my_kind file '$my_file' does not seem to be inside device mount point '$DEVICE_MOUNT_POINT'" log_err_add "please use a $my_kind file path that starts with '$DEVICE_MOUNT_POINT/'" exit "$ERR" fi "$CMD_expr" match "$my_file" '.*/\.\./.*' >/dev/null 2>/dev/null if test "$?" = 0; then log_err "user-specified $my_kind file '$my_var' contains '/../' in path" log_err_add "maybe somebody is trying to break $PROG?" log_err_add "I give up, sorry" exit "$ERR" fi log_info "overwriting $my_kind file '$my_file' inside device '$DEVICE'..." fi exec_cmd_noquit "$CMD_dd" "if=/dev/zero" "of=$my_file" bs=1 count=1 if test "$ERR" != 0; then log_err "failed to create or truncate '$my_file' to zero bytes" log_err_add "maybe device '$DEVICE' is full or mounted read-only?" exit "$ERR" fi eval "$my_var='$my_file'" } create_loop_file() { create_loop_or_zero_file loop LOOP_FILE "$LOOP_FILE" CLEANUP_1="'$CMD_rm' -f '$LOOP_FILE'" # loop file length is = device size truncated down to a multiple of its block size: # avoids annoying problems if device's last block has an odd length capture_cmd DEVICE_BLOCK_SIZE "$CMD_stat" -c %o "$LOOP_FILE" log_info "device file-system block size = $DEVICE_BLOCK_SIZE bytes" if test "$DEVICE_BLOCK_SIZE" = "" -o "$DEVICE_BLOCK_SIZE" -lt 512; then # paranoia... DEVICE_BLOCK_SIZE=512 fi : $(( DEVICE_SIZE_IN_BLOCKS = DEVICE_SIZE_IN_BYTES / DEVICE_BLOCK_SIZE )) : $(( LOOP_SIZE_IN_BYTES = DEVICE_SIZE_IN_BLOCKS * DEVICE_BLOCK_SIZE )) log_info "device usable size = $LOOP_SIZE_IN_BYTES bytes" if test "$USER_LOOP_SIZE_IN_BYTES" != ""; then # only accept user-specified new-size if smaller than maximum allowed, # and in any case truncate it down to a multiple of device block size if test "$USER_LOOP_SIZE_IN_BYTES" -lt "$LOOP_SIZE_IN_BYTES"; then : $(( LOOP_SIZE_IN_BYTES = USER_LOOP_SIZE_IN_BYTES / DEVICE_BLOCK_SIZE * DEVICE_BLOCK_SIZE )) fi log_info "sparse loop file will be $LOOP_SIZE_IN_BYTES bytes long (user specified $USER_LOOP_SIZE_IN_BYTES bytes)" fi exec_cmd "$CMD_dd" if=/dev/zero of="$LOOP_FILE" bs=1 count=1 seek="$(( LOOP_SIZE_IN_BYTES - 1 ))" } create_loop_file remount_device_ro() { log_info "unmounting device '$DEVICE' and remounting it read-only using kernel driver" exec_cmd "$CMD_umount" "$DEVICE" exec_cmd "$CMD_fsmount_kernel" "$DEVICE" "$DEVICE_MOUNT_POINT" -o ro -t "$DEVICE_FSTYPE" } remount_device_rw() { log_info "unmounting device '$DEVICE' and remounting it read-write" exec_cmd "$CMD_umount" "$DEVICE" exec_cmd "$CMD_mount" "$DEVICE" "$DEVICE_MOUNT_POINT" -o "$DEVICE_MOUNT_OPTS_RW" -t "$DEVICE_FSTYPE" } # detect unsupported corner cases, for example: # 1) source file systems without FIEMAP support and too large for FIBMAP # 2) other inconsistencies (which?) early_remap_validate() { log_info "launching '$CMD_fsremap' in simulated mode for pre-validation" exec_cmd "$CMD_fsremap" -q $my_OPTS_fsremap -n -- "$DEVICE" "$LOOP_FILE" } remount_device_ro early_remap_validate remount_device_rw connect_loop_device() { capture_cmd LOOP_DEVICE "$CMD_losetup" -f exec_cmd "$CMD_losetup" "$@" "$LOOP_DEVICE" "$LOOP_FILE" log_info "connected loop device '$LOOP_DEVICE' to file '$LOOP_FILE'" CLEANUP_2="'$CMD_losetup' -d '$LOOP_DEVICE'" } connect_loop_device disconnect_loop_device() { local my_iter=0 # loop device sometimes needs a little time to become free... for my_iter in 1 2 3 4; do exec_cmd "$CMD_sync" if test "$my_iter" != 1 -a "$CMD_sleep" != ""; then "$CMD_sleep" 5 exec_cmd "$CMD_sync" fi if test "$my_iter" != 4; then "$CMD_losetup" -d "$LOOP_DEVICE" && break else exec_cmd "$CMD_losetup" -d "$LOOP_DEVICE" fi done log_info "disconnected loop device '$LOOP_DEVICE' from file '$LOOP_FILE'" CLEANUP_2= } format_loop_device() { log_info "formatting loop device '$LOOP_DEVICE' with file-system type '$FSTYPE'..." exec_cmd "$CMD_mkfs" -t "$FSTYPE" $OPTS_mkfs "$LOOP_DEVICE" } format_loop_device mount_loop_file() { if test "$LOOP_MOUNT_POINT" = ""; then LOOP_MOUNT_POINT="$TMP_DIR/fstransform.loop.$$" exec_cmd "$CMD_mkdir" "$LOOP_MOUNT_POINT" else "$CMD_expr" match "$LOOP_MOUNT_POINT" "/.*" >/dev/null 2>/dev/null ERR="$?" if test "$ERR" != 0; then log_warn "user-specified loop file mount point '$LOOP_MOUNT_POINT' should start with '/'" log_warn_add "i.e. it should be an absolute path." log_warn_add "$PROG cannot ensure that '$LOOP_MOUNT_POINT' is outside '$DEVICE_MOUNT_POINT'" if test "$OPT_ASK_QUESTIONS" = "no"; then log_err_add "you could examine the previous warning and decide to continue at your own risk" log_err_add "but this is a non-interactive run, so $PROG will exit now" log_info "exiting." exit "$ERR" else log_warn_add "continue at your own risk" log_warn_add log_warn_add_prompt "press ENTER to continue, or CTRL+C to quit: " read_user_answer fi else "$CMD_expr" match "$LOOP_MOUNT_POINT" "$DEVICE_MOUNT_POINT/.*" >/dev/null 2>/dev/null if test "$?" = 0; then log_err "user-specified loop file mount point '$LOOP_MOUNT_POINT' seems to be inside '$DEVICE_MOUNT_POINT'" log_err_add "maybe somebody is trying to break $PROG and lose data?" log_err_add "I give up, sorry" exit 1 fi fi fi log_info "mounting loop device '$LOOP_DEVICE' on '$LOOP_MOUNT_POINT' $1..." local my_mount_opts="$LOOP_MOUNT_OPTS_RW" if test "$1" = readonly; then my_mount_opts="ro" fi exec_cmd "$CMD_mount" "$LOOP_DEVICE" "$LOOP_MOUNT_POINT" -t "$FSTYPE" -o "$my_mount_opts" log_info "loop device '$LOOP_DEVICE' mounted successfully." CLEANUP_3="'$CMD_rmdir' $LOOP_MOUNT_POINT" CLEANUP_4="'$CMD_umount' $LOOP_DEVICE" } mount_loop_file move_device_contents_into_loop_file() { if test "$OPT_PREALLOC" = yes; then log_info "preallocating loop file contents." log_info "this may take some time, please be patient..." OPTS_fsmove="$OPTS_fsmove --io=prealloc" else log_info "preliminary steps completed, now comes the delicate part:" log_info "$PROG will move '$DEVICE' contents into the loop file." log_warn "THIS IS IMPORTANT! if either the original device '$DEVICE'" log_warn_add "or the loop device '$LOOP_DEVICE' become FULL," log_warn_add log_warn_add " YOU WILL LOSE YOUR DATA !" log_warn_add log_warn_add "$PROG checks for enough available space," log_warn_add "in any case it is recommended to open another terminal, type" log_warn_add " watch df $DEVICE $LOOP_DEVICE" log_warn_add "and check that both the original device '$DEVICE'" log_warn_add "and the loop device '$LOOP_DEVICE' are NOT becoming full." log_warn_add "if one of them is becoming full (or both)," log_warn_add "you MUST stop $PROG with CTRL+C or equivalent." log_warn_add if test "$OPT_ASK_QUESTIONS" = "extra"; then log_warn_add "this is your chance to quit." log_warn_add_prompt "press ENTER to continue, or CTRL+C to quit: " read_user_answer fi log_info "moving '$DEVICE' contents into the loop file." log_info "this may take a long time, please be patient..." # do not remove $LOOP_FILE anymore: in a moment it will contain users' data! CLEANUP_1= fi exec_cmd "$CMD_fsmove" $OPTS_fsmove -- "$DEVICE_MOUNT_POINT" "$LOOP_MOUNT_POINT" --exclude "$LOOP_FILE" } move_device_contents_into_loop_file umount_and_fsck_loop_file() { log_info "unmounting and running '$CMD_fsck_target' (disk check) on loop file '$LOOP_FILE'" exec_cmd "$CMD_umount" "$LOOP_DEVICE" CLEANUP_4= exec_cmd_fsck "$CMD_fsck_target" $OPTS_fsck_target "$LOOP_DEVICE" exec_cmd "$CMD_sync" if test "$X_COPY_LOOP_FILE" != ""; then log_info "(internal option) copying loop file '$LOOP_FILE' to '$X_COPY_LOOP_FILE'" exec_cmd "$CMD_dd" bs=64k if="$LOOP_DEVICE" of="$X_COPY_LOOP_FILE" fi } umount_and_fsck_loop_file disconnect_loop_device clear_loop_file_prealloc_flag() { if test "$OPT_PREALLOC" = yes; then log_info "executing 'fsattr' to clear preallocation flags inside loop file '$LOOP_FILE'" exec_cmd "$CMD_fsattr" --fstype="$FSTYPE" --files=normal "$LOOP_FILE" fi } clear_loop_file_prealloc_flag create_zero_file() { if test "$OPT_CREATE_ZERO_FILE" != "yes"; then return 0 fi create_loop_or_zero_file zero ZERO_FILE "$ZERO_FILE" CLEANUP_5="'$CMD_rm' -f '$ZERO_FILE'" log_info "filling '$ZERO_FILE' with zeroes until device '$DEVICE' is full" log_info_add "needed by '$CMD_fsremap' to locate unused space." log_info_add "this may take a while, please be patient..." # trying to fill a device until it fails with "no space left on device" is not very nice # and can probably cause file-system corruption if device happens to be a loop-mounted file # which contains non-synced data. # to be safe, we 'sync' BEFORE and AFTER filling the device exec_cmd "$CMD_sync" # next command will fail with "no space left on device". # this is normal and expected. "$CMD_dd" if=/dev/zero of="$ZERO_FILE" bs=64k >/dev/null 2>/dev/null exec_cmd "$CMD_sync" log_info "file full of zeroes created successfully" } create_zero_file remount_device_ro_and_fsck() { #log_info "remounting device '$DEVICE' read-only" #exec_cmd "$CMD_mount" "$DEVICE" -o remount,ro #exec_cmd "$CMD_sync" # cannot safely perform disk check on a mounted device... it must be unmounted first! log_info "unmounting device '$DEVICE' before disk check" exec_cmd "$CMD_umount" "$DEVICE" log_info "running '$CMD_fsck_source' (disk check) on device '$DEVICE'" exec_cmd_fsck "$CMD_fsck_source" $OPTS_fsck_source "$DEVICE" exec_cmd "$CMD_sync" if test "$X_COPY_DEVICE" != ""; then log_info "(internal option) copying device '$DEVICE' to '$X_COPY_DEVICE'" exec_cmd "$CMD_dd" bs=64k if="$DEVICE" of="$X_COPY_DEVICE" fi log_info "mounting again device '$DEVICE' read-only with kernel driver" exec_cmd "$CMD_fsmount_kernel" "$DEVICE" "$DEVICE_MOUNT_POINT" -o ro -t "$DEVICE_FSTYPE" } remount_device_ro_and_fsck reconnect_and_remount_ro_loop_device_for_prealloc() { # losetup option "-r" means read-only connect_loop_device "-r" mount_loop_file readonly # update 'fsremap' options OPTS_fsremap="$OPTS_fsremap --io=prealloc --device-mount-point=$DEVICE_MOUNT_POINT --loop-mount-point=$LOOP_MOUNT_POINT --loop-device=$LOOP_DEVICE --cmd-losetup=$CMD_losetup" } if test "$OPT_PREALLOC" = yes; then reconnect_and_remount_ro_loop_device_for_prealloc fi remap_device_and_sync() { local my_OPTS_fsremap="--questions=$OPT_ASK_QUESTIONS $OPTS_fsremap" log_info "launching '$CMD_fsremap' in simulated mode" if test "$OPT_CREATE_ZERO_FILE" = "yes"; then exec_cmd "$CMD_fsremap" -q $my_OPTS_fsremap -n -- "$DEVICE" "$LOOP_FILE" "$ZERO_FILE" else exec_cmd "$CMD_fsremap" -q $my_OPTS_fsremap -n -- "$DEVICE" "$LOOP_FILE" fi log_info "launching '$CMD_fsremap' in REAL mode to perform in-place remapping." # starting to remap device, $ZERO_FILE will not exist anymore CLEANUP_5= if test "$OPT_CREATE_ZERO_FILE" = "yes"; then exec_cmd "$CMD_fsremap" -q $my_OPTS_fsremap --cmd-umount="$CMD_umount" -- "$DEVICE" "$LOOP_FILE" "$ZERO_FILE" else exec_cmd "$CMD_fsremap" -q $my_OPTS_fsremap --cmd-umount="$CMD_umount" -- "$DEVICE" "$LOOP_FILE" fi exec_cmd "$CMD_sync" if test "$X_COPY_LOOP_FILE" != ""; then log_info "(internal option) comparing transformed device '$DEVICE' with previously saved loop file '$X_COPY_LOOP_FILE'" # loop file may be smaller than device... # more exactly its length will be = device length rounded down to device block size "$CMD_dd" if="$DEVICE" bs="$DEVICE_BLOCK_SIZE" count="$DEVICE_SIZE_IN_BLOCKS" | "$CMD_cmp" - "$X_COPY_LOOP_FILE" || exit 1 fi } remap_device_and_sync fsck_device() { log_info "running again '$CMD_fsck_target' (disk check) on device '$DEVICE'" exec_cmd_fsck "$CMD_fsck_target" $OPTS_fsck_target "$DEVICE" } fsck_device final_mount_device() { log_info "mounting transformed device '$DEVICE'" exec_cmd "$CMD_mount" "$DEVICE" "$DEVICE_MOUNT_POINT" -t "$FSTYPE" log_info "completed successfully. your new '$FSTYPE' file-system is mounted at '$DEVICE_MOUNT_POINT'" } if test "$DEVICE_IS_INITIALLY_MOUNTED" = "yes"; then final_mount_device else log_info "completed successfully. device '$DEVICE' now contains '$FSTYPE' file-system" fi fstransform-0.9.4/fstransform/src/000077500000000000000000000000001345021500300172145ustar00rootroot00000000000000fstransform-0.9.4/fstransform/src/features.hh000077700000000000000000000000001345021500300263572../../fsremap/src/features.hhustar00rootroot00000000000000fstransform-0.9.4/fstransform/src/first.hh000077700000000000000000000000001345021500300252012../../fsremap/src/first.hhustar00rootroot00000000000000fstransform-0.9.4/fstransform/src/log.cc000077700000000000000000000000001345021500300242412../../fsremap/src/log.ccustar00rootroot00000000000000fstransform-0.9.4/fstransform/src/log.hh000077700000000000000000000000001345021500300242652../../fsremap/src/log.hhustar00rootroot00000000000000fstransform-0.9.4/fstransform/src/main.cc000066400000000000000000000020531345021500300204470ustar00rootroot00000000000000/* * fstransform - modify file-system internal data structures * * Copyright (C) 2016 Massimiliano Ghilardi * * 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, see . * * main.cc * Created on: Feb 29, 2016 * Author: max */ #include "first.hh" #include "transform.hh" // for ft_transform #define FT_MAIN(argc, argv) FT_NS ft_transform::main(argc, argv) int main(int argc, char ** argv) { return FT_MAIN(argc, argv); } fstransform-0.9.4/fstransform/src/mstring.cc000077700000000000000000000000001345021500300260452../../fsremap/src/mstring.ccustar00rootroot00000000000000fstransform-0.9.4/fstransform/src/mstring.hh000077700000000000000000000000001345021500300260712../../fsremap/src/mstring.hhustar00rootroot00000000000000fstransform-0.9.4/fstransform/src/transform.cc000066400000000000000000000350261345021500300215440ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * move.cc * * Created on: Feb 29, 2016 * Author: max */ #include "first.hh" #include "transform.hh" #if defined(FT_HAVE_STRING_H) # include // for strcmp() #elif defined(FT_HAVE_CSTRING) # include // for strcmp() #endif FT_NAMESPACE_BEGIN /** default constructor */ ft_transform::ft_transform() : quit_immediately(false) { } /** destructor. calls quit() */ ft_transform::~ft_transform() { quit(); } int ft_transform::init() { return err; } /** performs cleanup. called by destructor, you can also call it explicitly after (or instead of) run() */ void ft_transform::quit() { } bool ft_transform::is_initialized() const { return false; } /** return EISCONN if remapper is initialized, else call quit_io() and return 0 */ int ft_transform::check_is_closed() { int err = 0; if (is_initialized()) { ff_log(FC_ERROR, 0, "error: already initialized"); /* error is already reported, flip sign */ err = -EISCONN; } else // quit() to make sure we are not left in a half-initialized status quit(); return err; } /** return 0 if remapper is initialized, else ENOTCONN */ int ft_transform::check_is_open() { int err = 0; if (!is_initialized()) { ff_log(FC_ERROR, 0, "error: not initialized"); // quit() to make sure we are not left in a half-initialized status quit(); /* error is already reported, flip sign */ err = -ENOTCONN; } return err; } /** * high-level do-everything method. calls in sequence init(), run() and cleanup(). * return 0 if success, else error. */ int ft_transform::main(int argc, char ** argv) { ft_transform transformer; int err = transformer.init(argc, argv); if (err == 0 && !transformer.quit_immediately) err = transformer.run(); /* * note 1.2.2) fsmove::main() must check for unreported errors * and log them them with message "failed with unreported error" */ if (!ff_log_is_reported(err)) err = ff_log(FC_ERROR, err, "failed with unreported error"); return err; } /** print command-line usage to stdout and return 0 */ int ft_transform::usage(const char * program_name) { quit_immediately = true; ff_log(FC_NOTICE, 0, "Usage: %s [OPTION]... DEVICE FILESYSTEM_TYPE", program_name); ff_log(FC_NOTICE, 0, "Convert device filesystem to a different filesystem type,"); ff_log(FC_NOTICE, 0, "preserving its contents"); return ff_log(FC_NOTICE, 0, "Mandatory arguments to long options are mandatory for short options too.\n" " -- end of options. treat subsequent parameters as arguments\n" " even if they start with '-'\n" " -e, --exclude FILE... skip these files, i.e. do not move them.\n" " must be last argument\n" " -f, --force-run run even if some safety checks fail\n" " --io=posix use POSIX I/O and move files (default)\n" #ifdef FT_HAVE_FM_IO_IO_PREALLOC " --io=prealloc use POSIX I/O and preallocate files (do NOT move them)\n" #endif " --inode-cache-mem use in-memory inode cache (default)\n" " --inode-cache=DIR create and use directory DIR for inode cache\n" " --log-color=MODE set messages color. MODE is one of:" " auto (default), none, ansi\n" " --log-format=FMT set messages format. FMT is one of:\n" " msg (default), level_msg, time_level_msg,\n" " time_level_function_msg\n" " -n, --no-action, --simulate-run\n" " do not actually move any file or directory\n" " -q, --quiet be quiet\n" " -qq be very quiet, only print warnings or errors\n" " -v, --verbose be verbose, print what is being done\n" " -vv be very verbose, print a lot of detailed output\n" " -vvv be incredibly verbose (warning: prints LOTS of output)\n" " --help display this help and exit\n" " --version output version information and exit\n"); } /** output version information and return 0 */ int ft_transform::version() { quit_immediately = true; return ff_log(FC_NOTICE, 0, "fsmove (fstransform utilities) " FT_VERSION "\n" "Copyright (C) 2011-2014 Massimiliano Ghilardi\n" "\n" "License GPLv3+: GNU GPL version 3 or later .\n" "This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law.\n"); } int ft_transform::invalid_cmdline(const char * program_name, int err, const char * fmt, ...) { va_list args; va_start(args, fmt); err = ff_vlog(FC_ERROR, err, fmt, args); va_end(args); ff_log(FC_NOTICE, 0, "Try `%s --help' for more information", program_name); /* mark error as reported */ return err ? err : -EINVAL; } /** * parse command line and initialize all subsystems (job, I/O, log...) * return 0 if success, else error. * * implementation: parse command line, fill a fm_args and call init(const fm_args &) */ int ft_transform::init(int argc, char const* const* argv) { fm_args args; int err; ft_log_fmt format = FC_FMT_MSG; ft_log_level level = FC_INFO, new_level; ft_log_color color = FC_COL_AUTO; bool format_set = false; do { if ((err = check_is_closed()) != 0) break; if (argc == 0) { err = invalid_cmdline("fsmove", 0, "missing arguments: %s %s", LABEL[0], LABEL[1]); break; } const char * arg, * program_name = argv[0]; ft_size io_args_n = 0; bool allow_opts = true; // skip program_name while (err == 0 && --argc) { arg = * ++argv; /* -e is allowed even after '--', but must be last argument */ if (io_args_n == FC_ARGS_COUNT && argc > 0 && arg[0] == '-' && (!strcmp(arg, "-e") || !strcmp(arg, "--exclude")) ) { args.exclude_list = argv + 1; // -e uses all remaining arguments, so stop processing them break; } if (allow_opts && arg[0] == '-') { /* -- end of options*/ if (!strcmp(arg, "--")) allow_opts = false; /* -q, --quiet decrease verbosity by one */ /* -qq decrease verbosity by two */ /* -v, --verbose increase verbosity by one */ /* -vv increase verbosity by two */ /* -vvv increase verbosity by three */ else if ((new_level = FC_WARN, !strcmp(arg, "-qq")) || (new_level = FC_NOTICE, !strcmp(arg, "-q") || !strcmp(arg, "--quiet")) || (new_level = FC_DEBUG, !strcmp(arg, "-v") || !strcmp(arg, "--verbose")) || (new_level = FC_TRACE, !strcmp(arg, "-vv")) || (new_level = FC_DUMP, !strcmp(arg, "-vvv"))) { if (level == FC_INFO) level = new_level; else { err = invalid_cmdline(program_name, 0, "options -q, -qq, -v, -vv, -vvv, --quiet, --verbose are mutually exclusive"); break; } } else if (!strncmp(arg, "--log-color=", 12)) { /* --color=(auto|none|ansi) */ arg += 12; if (!strcmp(arg, "ansi")) color = FC_COL_ANSI; else if (!strcmp(arg, "none")) color = FC_COL_NONE; else color = FC_COL_AUTO; } else if (!strncmp(arg, "--log-format=", 13)) { /* --color=(auto|none|ansi) */ arg += 13; if (!strcmp(arg, "level_msg")) format = FC_FMT_LEVEL_MSG; else if (!strcmp(arg, "time_level_msg")) format = FC_FMT_DATETIME_LEVEL_MSG; else if (!strcmp(arg, "time_level_function_msg")) format = FC_FMT_DATETIME_LEVEL_CALLER_MSG; else format = FC_FMT_MSG; format_set = true; } else if (!strncmp(arg, "--x-log-", 8)) { /* --x-log-FILE=LEVEL */ arg += 8; const char * equal = strchr(arg, '='); ft_mstring logger_name(arg, equal ? equal - arg : strlen(arg)); ft_log_level logger_level = equal ? (ft_log_level) atoi(equal+1) : FC_INFO; ft_log::get_logger(logger_name).set_level(logger_level); } /* -f force run: degrade failed sanity checks from ERRORS (which stop execution) to WARNINGS (which let execution continue) */ else if (!strcmp(arg, "-f") || !strcmp(arg, "--force-run")) { args.force_run = true; } /* -n simulate run: do not read or write device blocks */ else if (!strcmp(arg, "-n") || !strcmp(arg, "--no-action") || !strcmp(arg, "--simulate-run")) { args.simulate_run = true; } /* --io=posix */ else if ((io_kind = FC_IO_POSIX, !strcmp(arg, "--io=posix")) #ifdef FT_HAVE_FM_IO_IO_PREALLOC || (io_kind = FC_IO_PREALLOC, !strcmp(arg, "--io=prealloc")) #endif ) { if (args.io_kind == FC_IO_AUTODETECT) args.io_kind = io_kind; else { #ifdef FT_HAVE_FM_IO_IO_PREALLOC err = invalid_cmdline(program_name, 0, "options --io=posix and --io=prealloc are mutually exclusive"); #else err = invalid_cmdline(program_name, 0, "option --io=posix can be specified only once"); #endif } } else if (!strcmp(arg, "--inode-cache-mem")) { args.inode_cache_path = NULL; } else if (!strncmp(arg, "--inode-cache=", 14)) { // do not allow empty dir name if (arg[14] != '\0') args.inode_cache_path = arg + 14; } else if (!strcmp(arg, "--help")) { return usage(args.program_name); } else if (!strcmp(arg, "--version")) { return version(); } else { err = invalid_cmdline(program_name, 0, "unknown option: '%s'", arg); break; } continue; } /** found an argument */ if (io_args_n < FC_ARGS_COUNT) args.io_args[io_args_n++] = arg; else err = invalid_cmdline(program_name, 0, "too many arguments"); } if (err != 0) break; /* if autodetect, use POSIX I/O */ if (args.io_kind == FC_IO_AUTODETECT) args.io_kind = FC_IO_POSIX; if (args.io_kind == FC_IO_POSIX || args.io_kind == FC_IO_PREALLOC) { if (io_args_n == 0) { err = invalid_cmdline(program_name, 0, "missing arguments: %s %s", LABEL[0], LABEL[1]); break; } else if (io_args_n == 1) { err = invalid_cmdline(program_name, 0, "missing argument: %s", LABEL[1]); break; } const char * source_root = args.io_args[FT_IO_NS fm_io::FC_SOURCE_ROOT]; if (args.inode_cache_path != NULL && source_root != NULL && (args.inode_cache_path[0] == '/') != (source_root[0] == '/')) { err = invalid_cmdline(program_name, 0, "relative/absolute path mismatch between source directory `%s'\n" "\tand inode-cache directory `%s':\n" "\tthey must be either both absolute, i.e. starting with `/',\n" "\tor both relative, i.e. NOT starting with `/'", source_root, args.inode_cache_path); break; } } } while (0); if (err == 0) { ft_log::get_root_logger().set_level(level); /* note 1.4.1) -v sets format FC_FMT_LEVEL_MSG */ /* note 1.4.2) -vv sets format FC_FMT_DATETIME_LEVEL_MSG */ if (!format_set) format = level < FC_DEBUG ? FC_FMT_DATETIME_LEVEL_MSG : level == FC_DEBUG ? FC_FMT_LEVEL_MSG : FC_FMT_MSG; // no dot alter appenders min_level ft_log_appender::reconfigure_all(format, FC_LEVEL_NOT_SET, color); err = init(args); } return err; } /** * initialize all subsystems (job, I/O, log...) using specified arguments * return 0 if success, else error. */ int ft_transform::init(const fm_args & args) { FT_IO_NS fm_io * io = NULL; int err = 0; switch (args.io_kind) { case FC_IO_POSIX: if ((err = check_is_closed()) != 0) break; io = new FT_IO_NS fm_io_posix(); break; #ifdef FT_HAVE_FM_IO_IO_PREALLOC case FC_IO_PREALLOC: if ((err = check_is_closed()) != 0) break; io = new FT_IO_NS fm_io_prealloc(); break; #endif default: ff_log(FC_ERROR, 0, "tried to initialize unknown I/O '%d': not POSIX" #ifdef FT_HAVE_FM_IO_IO_PREALLOC ", not PREALLOC" #endif , (int) args.io_kind); err = -ENOSYS; break; } return err; } /** * transformation algorithm entry point. calls transform() */ int ft_transform::run() { return transform(); } /** core of transformation algorithm */ int ft_transform::transform() { return 0 } FT_NAMESPACE_END fstransform-0.9.4/fstransform/src/transform.hh000066400000000000000000000060511345021500300215520ustar00rootroot00000000000000/* * fstransform - transform a file-system to another file-system type, * preserving its contents and without the need for a backup * * Copyright (C) 2011-2012 Massimiliano Ghilardi * * 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 . * * move.hh * * Created on: Feb 29, 2016 * Author: max */ #ifndef FSTRANSFORM_TRANSFORM_HH #define FSTRANSFORM_TRANSFORM_HH FT_NAMESPACE_BEGIN /** * class doing the core of recursive move work. */ class ft_transform { private: /** true if usage() or version() was called. */ bool quit_immediately; /** cannot call copy constructor */ ft_transform(const ft_transform &); /** cannot call assignment operator */ const ft_transform & operator=(const ft_transform &); /** display command-line usage to stdout and return 0 */ int usage(const char * program_name); /** output version information and return 0 */ int version(); static int invalid_cmdline(const char * program_name, int err, const char * fmt, ...); /** return EISCONN if transformer is initialized, else call quit() and return 0 */ int check_is_closed(); /** return 0 if transformer is initialized, else call quit() and return ENOTCONN */ int check_is_open(); /** initialize transformer */ int init(); /** core of transformation algorithm */ int transform(); /** show progress status and E.T.A. */ void show_progress(); public: /** default constructor */ ft_transform(); /** destructor. calls quit() */ ~ft_transform(); /** * high-level do-everything method. calls in sequence init(), run() and quit(). * return 0 if success, else error. */ static int main(int argc, char ** argv); bool is_initialized() const; /** * parse command line and initialize all subsystems (job, I/O, log...) * return 0 if success, else error. * * implementation: parse command line, fill a ft_args and call init(const ft_args &) */ int init(int argc, char const* const* argv); /** * initialize all subsystems (log...) using specified arguments */ int init(const ft_args & args); /** * transformation algorithm entry point. calls transform() */ int run(); /** * performs cleanup. called by destructor, you can also call it explicitly after (or instead of) run(). */ void quit(); }; FT_NAMESPACE_END #endif /* FSTRANSFORM_TRANSFORM_HH */ fstransform-0.9.4/fstransform/src/types.hh000077700000000000000000000000001345021500300252332../../fsremap/src/types.hhustar00rootroot00000000000000fstransform-0.9.4/tools/000077500000000000000000000000001345021500300152215ustar00rootroot00000000000000fstransform-0.9.4/tools/depcomp000077500000000000000000000560161345021500300166060ustar00rootroot00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2013-05-30.07; # UTC # Copyright (C) 1999-2014 Free Software Foundation, 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 2, 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 . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: fstransform-0.9.4/tools/ft_cxx_features.m4000066400000000000000000000024321345021500300206550ustar00rootroot00000000000000m4_define([FT_CXX_FEATURES], [ AC_CACHE_CHECK([whether $CXX supports explicit template instantiation], [ac_cv_cxx_have_template_instantiation], [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ template class ft_my_class { public: void apply(T *); }; template void ft_my_class::apply(T * arg) { } template class ft_my_class; ]], [[ ft_my_class dummy; ]])], [ac_cv_cxx_have_template_instantiation=yes], [ac_cv_cxx_have_template_instantiation=no] ) ]) AC_CACHE_CHECK([whether $CXX supports inhibiting template instantiation], [ac_cv_cxx_have_template_inhibition], [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ template class ft_my_class { public: void apply(T *); }; extern template class ft_my_class; ]], [[ ft_my_class dummy; ]])], [ac_cv_cxx_have_template_inhibition=yes], [ac_cv_cxx_have_template_inhibition=no] ) ]) if test "$ac_cv_cxx_have_template_instantiation" = yes -a "$ac_cv_cxx_have_template_inhibition" = yes; then AC_DEFINE([HAVE_EXTERN_TEMPLATE], [1], [define if C++ compiler supports forcing and inhibiting template instantiation]) fi ]) fstransform-0.9.4/tools/ft_cxx_flags.m4000066400000000000000000000026271345021500300201410ustar00rootroot00000000000000m4_define([FT_CXX_FLAGS], [ AC_CACHE_CHECK([whether $CXX accepts -Wall], [ac_cv_cxx_flag_Wall], [save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS -Wall" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]], [[ return 0; ]])], [ac_cv_cxx_flag_Wall=yes], [ac_cv_cxx_flag_Wall=no CXXFLAGS="$save_CXXFLAGS"] ) ]) AC_CACHE_CHECK([whether $CXX accepts -Wextra], [ac_cv_cxx_flag_Wextra], [save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS -Wextra" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]], [[ return 0; ]])], [ac_cv_cxx_flag_Wextra=yes], [ac_cv_cxx_flag_Wextra=no CXXFLAGS="$save_CXXFLAGS"] ) ]) AC_CACHE_CHECK([whether $CXX accepts -W], [ac_cv_cxx_flag_W], [save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS -W" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]], [[ return 0; ]])], [ac_cv_cxx_flag_W=yes], [ac_cv_cxx_flag_W=no CXXFLAGS="$save_CXXFLAGS"] ) ]) AC_CACHE_CHECK([whether $CXX accepts -Wno-missing-field-initializers], [ac_cv_cxx_flag_Wno_missing_field_initializers], [save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS -Wno-missing-field-initializers" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]], [[ return 0; ]])], [ac_cv_cxx_flag_Wno_missing_field_initializers=yes], [ac_cv_cxx_flag_Wno_missing_field_initializers=no CXXFLAGS="$save_CXXFLAGS"] ) ]) ]) fstransform-0.9.4/tools/ft_cxx_unordered_map.m4000066400000000000000000000023231345021500300216620ustar00rootroot00000000000000m4_define([FT_CXX_STD_UNORDERED_MAP], [AC_CACHE_CHECK([whether C++ library implements std::unordered_map], [ac_cv_cxx_have_std_unordered_map], [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #ifdef HAVE_UNORDERED_MAP #include #endif ]], [[ std::unordered_map my_map; ]])], [ac_cv_cxx_have_std_unordered_map=yes], [ac_cv_cxx_have_std_unordered_map=no])]) if test "$ac_cv_cxx_have_std_unordered_map" = yes; then AC_DEFINE([HAVE_STD_UNORDERED_MAP], [1], [define if C++ library implements std::unordered_map]) fi] ) m4_define([FT_CXX_STD_TR1_UNORDERED_MAP], [AC_CACHE_CHECK([whether C++ library implements std::tr1::unordered_map], [ac_cv_cxx_have_std_tr1_unordered_map], [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #ifdef HAVE_TR1_UNORDERED_MAP #include #endif ]], [[ std::tr1::unordered_map my_map; ]])], [ac_cv_cxx_have_std_tr1_unordered_map=yes], [ac_cv_cxx_have_std_tr1_unordered_map=no])]) if test "$ac_cv_cxx_have_std_tr1_unordered_map" = yes; then AC_DEFINE([HAVE_STD_TR1_UNORDERED_MAP], [1], [define if C++ library implements std::tr1::unordered_map]) fi] ) fstransform-0.9.4/tools/ft_need_funcs.m4000066400000000000000000000013251345021500300202660ustar00rootroot00000000000000m4_define([FT_NEED_ALL_FUNCS], [ ft_funcs_missing= for ft_func in $@ do : if test "`eval echo '$ac_cv_func_'$ft_func`" != "yes" then ft_funcs_missing="$ft_funcs_missing$ft_func " fi done if test "x$ft_funcs_missing" != "x" then as_fn_error $? "missing required functions: $ft_funcs_missing" fi ]) m4_define([FT_NEED_ANY_FUNC], [ ft_funcs_missing= ft_funcs_found= for ft_func in $@ do : ft_funcs_missing="$ft_funcs_missing$ft_func " if test "`eval echo '$ac_cv_func_'$ft_func`" = "yes" then ft_funcs_found=1 fi done if test "x$ft_funcs_found" = "x" then as_fn_error $? "least one of the following functions is required: $ft_funcs_missing" fi ]) fstransform-0.9.4/tools/ft_need_libs.m4000066400000000000000000000005511345021500300201010ustar00rootroot00000000000000m4_define([FT_NEED_ALL_LIBS], [ ft_libs_missing= for ft_lib in $@ do : if test "`eval echo '$ac_cv_lib_'$ft_lib`" != "yes" then ft_libs_missing="${ft_libs_missing}lib$(echo $ft_lib | sed 's/_/:/')() " fi done if test "x$ft_libs_missing" != "x" then as_fn_error $? "missing required library functions: $ft_libs_missing" fi ]) fstransform-0.9.4/tools/ft_output.m4000066400000000000000000000002431345021500300175130ustar00rootroot00000000000000m4_define([FT_OUTPUT], [[ sed -e 's/define \([A-Z]\)/define FT_\1/g' -e 's/undef \([A-Z]\)/undef FT_\1/g' < fsremap/src/config.hh > fsremap/src/ft_config.hh ]]) fstransform-0.9.4/tools/install-sh000077500000000000000000000345231345021500300172340ustar00rootroot00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2013-12-25.23; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. tab=' ' nl=' ' IFS=" $tab$nl" # Set DOITPROG to "echo" to test this script. doit=${DOITPROG-} doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: fstransform-0.9.4/tools/missing000077500000000000000000000153301345021500300166220ustar00rootroot00000000000000#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2013-10-28.13; # UTC # Copyright (C) 1996-2014 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # 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, 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 . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=http://www.perl.org/ flex_URL=http://flex.sourceforge.net/ gnu_software_URL=http://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: